我正在处理与onViewCreated中使用getString有关的IllegalStateException崩溃;查看堆栈跟踪,这通过getResources返回到requireContext,如果context为null,则抛出IllegalStateException。
我可能可以通过使用getContext()并检查是否为空来解决这个问题,但这让我想知道是否存在某些场景,其中在片段生命周期的onViewCreated步骤中上下文为空。
我的堆栈跟踪也显示了这些崩溃发生在onViewCreated中定义的CoroutineScopes中。
如果有任何关于这个主题的反馈,我将不胜感激,因为通过代码,我正确地调用了getString函数,没有任何奇怪的位置,如在导航之后。下面是堆栈跟踪。我在Android 13设备上运行这个应用程序。- 谢谢-谢谢
Exception java.lang.IllegalStateException:
at androidx.fragment.app.Fragment.requireContext (Fragment.java)
at androidx.fragment.app.Fragment.getResources (Fragment.java)
at androidx.fragment.app.Fragment.getString (Fragment.java:1053)
at com.example.MyFragment$onViewCreated$1$2.invokeSuspend (MyFragment.kt) //this leads me to think inside Coroutines is where its crashing.
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt)
at kotlinx.coroutines.DispatchedTask.run (DispatchedTask.kt)
at android.os.Handler.handleCallback (Handler.java:942)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loopOnce (Looper.java:226)
at android.os.Looper.loop (Looper.java:313)
at android.app.ActivityThread.main (ActivityThread.java:8757)
at java.lang.reflect.Method.invoke
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:604)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1067)
字符串
2条答案
按热度按时间kpbwa7wx1#
堆栈跟踪未指向
onViewCreated
。注意跟踪中的函数名实际上是onViewCreated$1$2
。这是为您在onViewCreated
中启动的协程创建的虚函数名。所以崩溃发生在onViewCreated
之后的某个时间,大概是在onDetach
之后,所以在那个时候上下文是空的。这是一种反模式,创建一个CoroutineScope并立即从它启动一个协程,而不首先将CoroutineScope存储在一个属性中,这样当它使用的东西超出范围时,您就可以取消它。您正在创建一个全局协同程序,并且可能也使用GlobalScope。
CoroutineScope().launch
是一种代码气味,因为它是一个全局协程,而不是在GlobalScope中启动的,这表明作者不确定他们在做什么。偶尔会用到全局协程,但在绝大多数情况下,您不希望您的协程是全局的。协程通常处理的东西超过几毫秒,所以如果它正在做的工作变得过时,你想取消它,以避免浪费资源和内存超过必要的时间。更重要的是,也有像您这样的情况,您试图获取不再可用的Context,因此触发了崩溃。
Android Fragments已经提供了
viewLifecycleOwner.lifecycleScope
,您可以从中启动协程。当Fragment视图被销毁时,它会自动取消所有它已经启动的协程,这可以保护您在不必要的时间内保留过时的视图引用,或者在上下文不再可用时尝试获取上下文。使用
Dispatchers.IO
启动协程也应该是罕见的,特别是在Android上,其中有太多的类要求它们只在主线程上被触及。Dispatchers.Main
应该是您的默认值,它已经是lifecycleScope
的默认值。Dispatchers.IO
用于调用 * 阻塞 * 代码。一般来说,您应该只在withContext(Dispatchers.IO) { }
中使用它来 Package 协程中的块代码。还要注意,如果suspend函数遵循约定,它们就不会阻塞。它们在内部使用所需的任何线程/调度器,因此在调用时不需要将它们 Package 在
withContext
中。eaf3rand2#
//检查片段是否附加到有效的上下文
字符串
//现在可以安全地访问资源和执行其他操作了
型
或者您也可以查看
requireActivity()。