嵌套Fragment场景下带ID的RecyclerView与CoordinatorLayout恢复崩溃求助
CoordinatorLayout$SavedState类找不到的异常 我之前也碰到过一模一样的问题——开发嵌套Fragment的时候,应用被系统因内存不足杀掉,恢复时直接抛出ClassNotFoundException: android.support.design.widget.CoordinatorLayout$SavedState。折腾了一阵后才搞明白,这是类加载器上下文不匹配导致的:系统恢复Fragment状态时,默认用的类加载器找不到support/AndroidX库中的内部类,尤其是嵌套Fragment场景下,状态传递过程中类加载器没有正确传递。
下面是几个亲测有效的解决方案,你可以根据自己的需求选择:
方案一:跳过不必要的视图状态保存
如果你不需要保存CoordinatorLayout的滚动位置或其他状态,可以直接在包含该布局的Fragment里重写onSaveInstanceState,不调用父类方法,只保存你自己需要的业务数据:@Override public void onSaveInstanceState(Bundle outState) { // 注释掉super调用,避免系统自动保存视图状态 // super.onSaveInstanceState(outState); // 只保存自定义业务数据 outState.putString("user_id", "12345"); }这个方法最简单,但如果需要保留CoordinatorLayout的状态就不适用。
方案二:强制设置正确的类加载器
问题的核心是恢复状态时用了错误的类加载器,所以我们可以在恢复前给Bundle手动设置应用的类加载器。
如果你是在Activity中管理嵌套Fragment,就在Activity的onCreate里加这段:@Override protected void onCreate(Bundle savedInstanceState) { if (savedInstanceState != null) { // 把应用自身的类加载器设置给保存状态的Bundle savedInstanceState.setClassLoader(getClassLoader()); } super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); }如果是父Fragment管理子Fragment,就在父Fragment的
onCreate里做同样的操作:@Override public void onCreate(Bundle savedInstanceState) { if (savedInstanceState != null) { savedInstanceState.setClassLoader(requireContext().getClassLoader()); } super.onCreate(savedInstanceState); }这个方法能从根源解决类加载器的问题,我自己就是用这个方案搞定的。
方案三:迁移到AndroidX(如果还在用support库)
如果你还在使用旧的android.support系列库,强烈建议迁移到AndroidX。AndroidX对Fragment的状态恢复逻辑做了不少优化,这类因类加载器导致的异常出现概率会低很多。方案四:手动处理视图状态恢复
在Fragment的onCreateView方法里,先给Bundle设置类加载器,再恢复视图状态:@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if (savedInstanceState != null) { savedInstanceState.setClassLoader(requireContext().getClassLoader()); } View rootView = inflater.inflate(R.layout.fragment_nested, container, false); // 手动恢复视图状态(如果有需要) if (savedInstanceState != null) { rootView.restoreHierarchyState(savedInstanceState); } return rootView; }
总结一下:这个异常本质是系统恢复Fragment时,用的类加载器找不到CoordinatorLayout的内部SavedState类,只要确保恢复过程中使用应用自身的类加载器,就能解决问题。
内容的提问来源于stack exchange,提问作者Faierbel

