android - 如何将协程范围限定为 fragment ,以便在 fragment 离开屏幕或被销毁时自动取消?

标签 android kotlin kotlin-coroutines android-jetpack-navigation

我有这个 fragment ,它只是在检索数据时用作启动屏幕。问题是,在配置更改或 Fragment 离开屏幕(用户导航出应用程序)时,它会在从 IO Coroutine block 返回并尝试在 Main Coroutine block 中执行导航时崩溃。

这是代码:

注: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)
            }
        }
    }
}

此外,我需要仅在检索数据后进行导航,但数据检索必须在 IO 线程上完成,并且在主线程上进行导航。

我一直在阅读有关确定协程范围的信息,但我仍然感到困惑/不确定它是如何工作的以及如何正确设置它。

最佳答案

我能够通过实现这样的东西来修复它:

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)
                }
            }
        }
    }
}

关于android - 如何将协程范围限定为 fragment ,以便在 fragment 离开屏幕或被销毁时自动取消?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60711661/

相关文章:

Android M - MediaRecorder 启动失败

elasticsearch - 我是如何达到 index.mapping.total_fields.limit 的?

java - 从哪里获取用于在 Java 或 Kotlin 中验证 JWT token 的公钥

Reactive SQL 客户端 (Quarkus/Vert.X) 中的 Kotlin 协程事务

kotlin - kotlinx.coroutines 中的 CoroutineContext 和 Job 有什么区别?

android - 评估指令时出现 Proguard 错误

java - Android Java 服务器套接字无法连接

android - 如果 Activity 进入画中画模式,则不会调用 onActivityResult

android - 自定义注释,如用于 android viewBinding 的 Butterknifes "@OnClick"

kotlin - 如何启动并行协程并返回结果