Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/190.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 如何将一个协同程序定义为一个片段,以便在片段离开屏幕或被销毁时自动取消?_Android_Kotlin_Kotlin Coroutines_Android Jetpack Navigation - Fatal编程技术网

Android 如何将一个协同程序定义为一个片段,以便在片段离开屏幕或被销毁时自动取消?

Android 如何将一个协同程序定义为一个片段,以便在片段离开屏幕或被销毁时自动取消?,android,kotlin,kotlin-coroutines,android-jetpack-navigation,Android,Kotlin,Kotlin Coroutines,Android Jetpack Navigation,我有这个片段,它只是在检索数据时作为一个启动屏幕。问题是,在配置更改时,或者如果片段在屏幕外(用户导航出应用程序),当它从IO协同程序块返回并尝试在主协同程序块中执行导航时,它会崩溃 代码如下: 注意:viewModel.repository.initData()进行改装调用,并在数据不存在或过时时将响应持久化到房间数据库 class LoadingFragment : Fragment() { private lateinit var viewModel: LoadingViewMo

我有这个片段,它只是在检索数据时作为一个启动屏幕。问题是,在配置更改时,或者如果片段在屏幕外(用户导航出应用程序),当它从IO协同程序块返回并尝试在主协同程序块中执行导航时,它会崩溃

代码如下:

注意:
viewModel.repository.initData()
进行改装调用,并在数据不存在或过时时将响应持久化到房间数据库

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

我可以通过实现如下内容来修复它:

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

您不必自己设置,只需使用
viewModelScope.launch在
LoadingViewModel
内的
viewModelScope
中运行任务即可{
。@EpicPandaForce我已经尝试过了,但无法让它与导航同步执行。这意味着我只想在数据初始化后进行导航。如果没有多个不同的协同程序,可以只使用已经限定到片段生命范围的程序,
lifecycleScope
viewModel.repository、 initData()
应该是一个挂起函数,可以正确处理后台工作并更新主线程上的实时数据。因此,根本没有理由在片段本身中与调度程序发生冲突。您可能甚至不需要存储库,我也不知道为什么有人想将它们强行塞进他们的项目中。您想要Vie吗wModelScope,可能是
LiveData
或不是建立在完全不相关的抽象之上的东西,而不是使用。您不必自己设置它,只需在
LoadingViewModel
内的
viewModelScope
中运行任务,使用
viewModelScope.launch{
。@EpicPandaForce我已经尝试过了,但无法让它与导航同步执行。这意味着我只想在数据初始化后进行导航。如果没有多个不同的协同程序,可以只使用已经限定到片段生命范围的程序,
lifecycleScope
viewModel.repository、 initData()
应该是一个挂起函数,可以正确处理后台工作并更新主线程上的实时数据。因此,根本没有理由在片段本身中与调度程序发生冲突。您可能甚至不需要存储库,我也不知道为什么有人想将它们强行塞进他们的项目中。您想要Vie吗wModelScope,可能是
LiveData
,或者不是建立在完全无关的抽象之上的东西,而是使用