Android 一种关于解决 No view found for id xxxx for fragment xxxx 问题的方案

 一、问题描述

       因为一直在参加比赛开发一款 APP ,然后今天在测试的时候发现了一个问题,即当打开进入 APP 后,走过以下路径

近期记录——》班级——》打开班级详情——》个人中心——》当前课堂 时(下面的动图为已修复后的路径演示),出现了软件闪退的情况。

Android 一种关于解决 No view found for id xxxx for fragment xxxx 问题的方案_第1张图片

       经过查找,找到了软件崩溃时的错误记录如下:

2019-02-25 14:49:56.735 12007-12015/? E/art: Failed sending reply to debugger: Broken pipe
2019-02-25 14:49:57.580 12007-12042/? E/OpenGLRenderer: hwui_debug::CanvasContext createSurface sur=0x0, isValid =0
2019-02-25 14:49:58.807 12007-12042/com.example.smartclass E/OpenGLRenderer: hwui_debug::CanvasContext createSurface sur=0x0, isValid =0
2019-02-25 14:50:03.367 12007-12042/com.example.smartclass E/OpenGLRenderer: hwui_debug::CanvasContext createSurface sur=0x0, isValid =0
2019-02-25 14:50:10.292 12007-12007/com.example.smartclass E/FragmentManager: No view found for id 0x7f0900b4 (com.example.smartclass:id/recentRecordStatisticsViewPager) for fragment RecentOverallStudentStatusRankingsFragment{8a0f94c #2 id=0x7f0900b4 android:switcher:2131296436:0}
2019-02-25 14:50:10.292 12007-12007/com.example.smartclass E/FragmentManager: Activity state:
2019-02-25 14:50:10.350 12007-12007/com.example.smartclass E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.smartclass, PID: 12007
    java.lang.IllegalArgumentException: No view found for id 0x7f0900b4 (com.example.smartclass:id/recentRecordStatisticsViewPager) for fragment RecentOverallStudentStatusRankingsFragment{8a0f94c #2 id=0x7f0900b4 android:switcher:2131296436:0}
        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1454)
        at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852)
        at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3269)
        at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:3229)
        at android.support.v4.app.Fragment.performActivityCreated(Fragment.java:2466)
        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1483)
        at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852)
        at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3269)
        at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:3229)
        at android.support.v4.app.Fragment.performActivityCreated(Fragment.java:2466)
        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1483)
        at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
        at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:797)
        at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2625)
        at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2411)
        at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366)
        at android.support.v4.app.FragmentManagerImpl.execSingleAction(FragmentManager.java:2243)
        at android.support.v4.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:654)
        at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:146)
        at android.support.v4.view.ViewPager.populate(ViewPager.java:1244)
        at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:669)
        at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:631)
        at android.support.v4.view.ViewPager.setCurrentItem(ViewPager.java:612)
        at android.support.design.widget.TabLayout$ViewPagerOnTabSelectedListener.onTabSelected(TabLayout.java:2831)
        at android.support.design.widget.TabLayout.dispatchTabSelected(TabLayout.java:1608)
        at android.support.design.widget.TabLayout.selectTab(TabLayout.java:1601)
        at android.support.design.widget.TabLayout.selectTab(TabLayout.java:1569)
        at android.support.design.widget.TabLayout$Tab.select(TabLayout.java:1874)
        at android.support.design.widget.TabLayout$TabView.performClick(TabLayout.java:2059)
        at android.view.View$PerformClick.run(View.java:22695)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:185)
        at android.app.ActivityThread.main(ActivityThread.java:6615)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:916)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:806)

二、问题分析

       通过分析报错,我们可以看到崩溃的原因是

No view found for id 0x7f0900b4 (com.example.smartclass:id/recentRecordStatisticsViewPager) for fragment RecentOverallStudentStatusRankingsFragment{8a0f94c #2 id=0x7f0900b4 android:switcher:2131296436:0}

也就是说,在 fragment 中查找不到 id 为 recentRecordStatisticsViewPager 的组件。

       但是为什么会出现这种情况呢,我进行了一下软件的整体结构分析,这个 APP 打开后即用 TabLayout + ViewPager 实现了一个底部导航栏,然后在近期记录这个子页面中,又再次使用了 TabLayout + ViewPager 实现了一个顶部导航栏,紧接着在班级这个子页面下,使用 ExpandableList 实现了一个可伸缩的列表,之后在列表的子项目中又再次使用 TabLayout + ViewPager 实现了两个小的分标签页面。

       从整体的结构入手,排查代码同时上网查找资料,网上提示的最多的一种是在 Fragment 中嵌套的 Fragment 如果想要获取 FragmentManager 需要使用 fragment.getChildFragmentManager() 而不是 fragment.getFragmentManager(),但是这种原因我提前已经考虑过了,所以问题不在这里。

       第二个可能性是出在 ViewPager 上面,进行资料的查找后,发现 ViewPager 工作机制是这样的:

在使用 ViewPager 与 Fragment 的时候,ViewPager 会自动缓存一页内的数据,如下图:

Android 一种关于解决 No view found for id xxxx for fragment xxxx 问题的方案_第2张图片

       所以当我们当前处在 页面2 的时候,页面1 和 页面3 的 View 实际上已经创建好了,所以在我们拖动的时候是可以看见他们的界面的。但是当我们的页面处在 页面1 的时候,页面3 实际上就已经销毁了,直到跳转到 页面2 的时候,页面3 才会创建 View 。也就是说,每次他都是只缓存相邻的一个页面的,而当前页面的相邻的第二个开始的页面都会被销毁。

       这样我们也就找到了问题所在,即当我们从 近期记录 跳转到 个人中心 的页面后,近期记录 的页面其实就已经被销毁了,所以才会发生 “ 在 fragment 中查找不到 id 为 recentRecordStatisticsViewPager 的组件 ” 这样的问题。

三、解决方法

       找到了问题所在,想要解决问题就很简单了,只需要将 ViewPager 的缓存页面数增加到两页,那么当我们访问 个人中心 页面的时候 近期记录 页面就不会被销毁了,这样当我们再点击回去的时候,就可以正常的进行访问了,解决的代码如下:

ViewPager.setOffscreenPageLimit(2);

 

你可能感兴趣的:(Android)