由 java.lang.IllegalStateException 引起:无法为分离的片段创建 ViewModelProvider

Posted

技术标签:

【中文标题】由 java.lang.IllegalStateException 引起:无法为分离的片段创建 ViewModelProvider【英文标题】:Caused by java.lang.IllegalStateException: Can't create ViewModelProvider for detached fragment 【发布时间】:2018-10-19 04:24:27 【问题描述】:

我需要一些帮助来解决以下崩溃问题。我正在通过在viewpager 中调用fragment 来刷新我在Activity 中的重启列表以刷新其列表。以下是崩溃的堆栈跟踪:

Caused by java.lang.IllegalStateException: Can't create ViewModelProvider for detached fragment
       at android.arch.lifecycle.ViewModelProviders.checkActivity(ViewModelProviders.java:51)
       at android.arch.lifecycle.ViewModelProviders.of(ViewModelProviders.java:105)
       at com.ui.fragments.mainpagerfragments.ConversationListFragment.searchConversation(ConversationListFragment.java:383)
       at com.ui.activities.HomeActivity.onRestart(HomeActivity.java:288)
       at android.app.Instrumentation.callActivityOnRestart(Instrumentation.java:1256)
       at android.app.Activity.performRestart(Activity.java:6365)
       at android.app.Activity.performResume(Activity.java:6376)
       at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3299)
       at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3345)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1532)
       at android.os.Handler.dispatchMessage(Handler.java:111)
       at android.os.Looper.loop(Looper.java:207)
       at android.app.ActivityThread.main(ActivityThread.java:5728)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679)

从活动 onRestart 调用:

((MyListFragment) adapter.getFragmentAtPosition(0)).search("");

片段中的方法:

public void search(String query) 

        query = "%" + query + "%";
        if (myListViewModel == null) 
            myListViewModel = ViewModelProviders.of(this, viewModelFactory).get(MyListViewModel.class);
        
        if (myListViewModel.mList != null && myListViewModel.mList.hasActiveObservers()) 
            myListViewModel.mList.removeObservers(this);
        
        myListViewModel.getFilteredList(query).observe(this, mainObserver);
    

【问题讨论】:

发布您的代码。 已更新相关代码补丁,因为我无法在此处发布完整代码 【参考方案1】:

如果您使用的是 viewpager,请确保相应的片段实际上已附加到其活动(这是错误试图告诉您的内容)。片段可能不可见,因此它没有附加(取决于视图寻呼机的配置方式)。

快速而肮脏的修复:

public void search(String query) 

    if(!isAdded()) return; //<---- returns if the fragment is not attached

    query = "%" + query + "%";
    if (myListViewModel == null) 
        myListViewModel = ViewModelProviders.of(this, viewModelFactory).get(MyListViewModel.class);
    
    if (myListViewModel.mList != null && myListViewModel.mList.hasActiveObservers()) 
        myListViewModel.mList.removeObservers(this);
    
    myListViewModel.getFilteredList(query).observe(this, mainObserver);

但是,您应该重新调查您的架构,因为这些检查通常会暗示一些其他代码异味。当您使用新的 Android 架构模式时,应该不需要此检查,因为生命周期模式会为您处理所有这些:https://developer.android.com/topic/libraries/architecture/lifecycle

所以,基本上,你不应该直接调用片段的任何函数,而是调用相应的业务逻辑,通知片段更新它的视图。

【讨论】:

isAttach() 方法未找到...如果片段在同一方法中分离,我可以附加片段吗? 喜欢 if(isDetached()) activity.getSupportFragmentManager().beginTransaction() .attach(this) .commitAllowingStateLoss(); 对不起,我的错:应该是isAdded()。您不应尝试将片段附加到位并假设其余代码将起作用,因为附加过程是异步的,除非您等待附件,否则该函数可能仍然会失败。同样,考虑对您的代码进行一些重构。此处声明:developer.android.com/reference/android/arch/lifecycle/… 您应该在创建片段时创建一次模型并在相应的函数中更新模型。 @DenisLoh 你能演示一下只将业务逻辑从一个片段更新到另一个片段而不调用它们的方法的方法吗?【参考方案2】:

由于错误是片段尚未附加,因此需要在我们确定片段实际附加时执行。这是这样做的好方法;通过将代码放入覆盖方法 onAttach

@Override
public void onAttach(Context context) 
    super.onAttach(context);
    myListViewModel = ViewModelProviders.of(this, viewModelFactory).get(MyListViewModel.class);

【讨论】:

请解释您的答案 - 究竟是什么问题以及您是如何解决的? @Markus 认为这很明显为什么要修复它,以及我如何修复它就是答案。但我可以在答案中解释更多。请删除您的反对票。

以上是关于由 java.lang.IllegalStateException 引起:无法为分离的片段创建 ViewModelProvider的主要内容,如果未能解决你的问题,请参考以下文章

org.xml.sax.SAXNotRecognizedException:无法识别功能“http://javax.xml.XMLConstants/feature/secure-processing

jQuery 插件可由控制台触发,但不能由函数触发 - 为啥会这样?

常用宏定义 - 由角度转换弧度由弧度转换角度

由 coercion 引入的 NAs 由 knn 中的 coercionError 引入

如何区分两个“onpause”事件 - 由单击“暂停”按钮引起,以及由到达媒体片段末尾引起?

Nginx实现动静结合(动态资源由tomcat管理: 静态资源由Nginx管理)