Как добавить сопрограмму к фрагменту, чтобы он автоматически отменялся, когда фрагмент отключен от экрана или уничтожен? - PullRequest
0 голосов
/ 16 марта 2020

У меня есть этот фрагмент, который просто служит экраном spla sh, пока данные извлекаются. Проблема заключается в том, что при изменении конфигурации или если фрагмент находится за пределами экрана (пользователь вышел из приложения), он падает, когда возвращается из блока IO Coroutine и пытается выполнить навигацию в блоке Main Coroutine.

Вот код:

Примечание: viewModel.repository.initData() делает вызов Retrofit и сохраняет ответ на базу данных Room, если данные не существуют или устарели.

class LoadingFragment : Fragment() {

    private lateinit var viewModel: LoadingViewModel

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

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewModel = ViewModelProvider(this).get(LoadingViewModel::class.java)
        CoroutineScope(Dispatchers.IO).launch {
            // Small delay so the user can actually see the splash screen
            // for a moment as feedback of an attempt to retrieve data.
            delay(250)
            try {
                viewModel.repository.initData()
                CoroutineScope(Dispatchers.Main).launch {
                    findNavController().navigate(R.id.action_loadingFragment_to_mainFragment)
                }
            } catch (e: IOException) {
                findNavController().navigate(R.id.action_loadingFragment_to_errorFragment)
            }
        }
    }
}

Также мне нужно навигация должна осуществляться только после извлечения данных, но поиск данных должен выполняться в потоке ввода-вывода и в основном потоке.

Я читал о том, как определить область действия Coroutine, но я все еще в замешательстве / не знаю, как это работает и как правильно его настроить.

1 Ответ

0 голосов
/ 17 марта 2020

Мне удалось это исправить, реализовав что-то вроде этого:

class LoadingFragment : Fragment() {

    private lateinit var viewModel: LoadingViewModel

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

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewModel = ViewModelProvider(this).get(LoadingViewModel::class.java)
        lifecycleScope.launch {
            withContext(Dispatchers.IO) {
                // Small delay so the user can actually see the splash screen
                // for a moment as feedback of an attempt to retrieve data.
                delay(250)
                try {
                    viewModel.initData()
                    withContext(Dispatchers.Main) {
                        findNavController().navigate(R.id.action_loadingFragment_to_mainFragment)
                    }
                } catch (e: IOException) {
                    findNavController().navigate(R.id.action_loadingFragment_to_errorFragment)
                }
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...