Исправление багов во View‑фрагменте, потоках и работе с LocationManager

View и Context нельзя получать в конструкторе Fragment; работу нужно привязать к lifecycle, геолокацию — к разрешениям, а UI обновлять только на Main. Порог проверяют после увеличения счётчика.

Короткий ответ

Что ответить на собеседовании

View и Context нельзя получать в конструкторе Fragment; работу нужно привязать к lifecycle, геолокацию — к разрешениям, а UI обновлять только на Main. Порог проверяют после увеличения счётчика.

Подробный разбор

Ответ с пояснениями

Условие

Найдите и исправьте ошибки в следующем коде фрагмента на Kotlin. Программа должна показывать количество нажатий, менять текст кнопки и после достижения нужного количества запускать запрос к LocationManager из отдельного потока, однако в текущей реализации нарушены правила жизненного цикла фрагмента и работы с потоками. Предоставьте исправленную версию.

class Frmt(var targetCount: Int) : Fragment() {

    private val contextRef = requireContext()
    private val textView: TextView = requireView().findViewById(R.id.tv)
    private val button: Button = requireView().findViewById(R.id.btn)

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        return inflater.inflate(R.layout.asdasd, container, true)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        var clicks = 0
        textView.text = "Для подтверждения операции нажмите далее $targetCount раз"
        button.text = "Нажать"
        button.setOnClickListener {
            if (clicks < targetCount) {
                clicks += 1
            } else {
                Thread {
                    (contextRef.getSystemService(Context.LOCATION_SERVICE) as LocationManager)
                        .requestLocationUpdates(
                            LocationManager.GPS_PROVIDER,
                            500,
                            500f
                        ) {
                            val result = executeRequest(
                                it.latitude,
                                it.longitude
                            )

                            Handler().post {
                                if (result) {
                                    textView.text = "Операция произведена успешно"
                                } else {
                                    throw Exception("Операция произведена с ошибкой, повторите позже")
                                }
                            }
                        }
                }
            }
        }
    }
}

Ответ

View и Context нельзя получать в конструкторе Fragment; работу нужно привязать к lifecycle, геолокацию — к разрешениям, а UI обновлять только на Main. Порог проверяют после увеличения счётчика.

Исправленная структура обработчика после получения View в onViewCreated:

var clicks = 0
var started = false
button.setOnClickListener {
    if (started) return@setOnClickListener
    clicks++
    if (clicks < targetCount) return@setOnClickListener
    started = true
    viewLifecycleOwner.lifecycleScope.launch {
        try {
            val location = awaitAuthorizedLocation()
            val ok = withContext(Dispatchers.IO) {
                executeRequest(location.latitude, location.longitude)
            }
            textView.text = if (ok) "Готово" else "Не удалось выполнить операцию"
        } catch (cancelled: CancellationException) {
            throw cancelled
        } catch (error: Exception) {
            textView.text = "Повторите попытку позже"
        } finally {
            started = false
        }
    }
}

Это фрагмент исправления, не самостоятельный класс: awaitAuthorizedLocation должна проверять runtime-разрешение, иметь timeout и снимать listener при отмене. targetCount передают через arguments/SavedStateHandle, inflate вызывают с attachToRoot=false, ссылки binding очищают в onDestroyView. Если операция должна переживать пересоздание View, счётчик и выполнение переносят во ViewModel. Thread без Looper и Handler() без явного Main из исходника здесь не нужны.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее