java.lang.IllegalArgumentException: No view found for id 0xad7b9d70 (unknown) for fragment, 爬坑

Posted 苦逼程序员_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java.lang.IllegalArgumentException: No view found for id 0xad7b9d70 (unknown) for fragment, 爬坑相关的知识,希望对你有一定的参考价值。

java.lang.IllegalArgumentException: No view found for id 0xad7b9d70 (unknown) for fragment, 爬出一个findViewById的坑

最近遇到一个比较奇怪且难定位的异常,是由新功能开发而导致的,在4.4模拟器上面初始化某个界面的时候会出现崩溃,崩溃信息如下。这个异常在真机以及5.0以上的模拟器上都不会出现。

java.lang.IllegalArgumentException: No view found for id 0xad7b9d70 (unknown) for fragment MyFragmentad792440 #0 id=0xad7b9d70 android:switcher:-1384407696:0
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1102)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1290)
    at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:801)
    at android.support.v4.app.FragmentManagerImpl.execSingleAction(FragmentManager.java:1638)
    at android.support.v4.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:679)
    at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:143)
    at android.support.v4.view.ViewPager.populate(ViewPager.java:1240)
    at android.support.v4.view.ViewPager.populate(ViewPager.java:1088)
    at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1614)
    at android.view.View.measure(View.java:16497)
    at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:719)
    at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:455)
    at android.view.View.measure(View.java:16497)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
    at android.view.View.measure(View.java:16497)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
    at android.view.View.measure(View.java:16497)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
    at android.view.View.measure(View.java:16497)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
    at android.view.View.measure(View.java:16497)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125)
    at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1404)
    at android.widget.LinearLayout.measureVertical(LinearLayout.java:695)
    at android.widget.LinearLayout.onMeasure(LinearLayout.java:588)
    at android.view.View.measure(View.java:16497)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2291)
    at android.view.View.measure(View.java:16497)

新功能的界面逻辑还算简单,一个viewPager + 两个fragment组成,异常报出来的信息是其中一个fragment找不到id为0xad7b9d70的view。堆栈信息全部都是源码内的,没有找到容易定位的关键信息。于是很自然的顺着异常报出来的信息进入MyFragment里面去看逻辑(掉进坑里),毫无疑问,找不到明显的问题。于是把MyFragment从viewPagerAdapter内移除,只加载一个Fragment,发现异常依旧,并且异常信息显示为另一个OtherFragment了。再把OtherFragment也移除掉,界面正常加载了,看来应该是Fragment加载进viewPager的过程种出现了问题。

在查看了自定义的CustomViewPager代码找不到问题后,跟着堆栈信息进入FragmentManager.moveToState()源码查看,发现了下面一段代码:

container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
if (container == null && !f.mRestored) 
    String resName;
    try 
        resName = f.getResources().getResourceName(f.mContainerId);
     catch (NotFoundException e) 
        resName = "unknown";
    
    throwException(new IllegalArgumentException(
            "No view found for id 0x"
            + Integer.toHexString(f.mContainerId) + " ("
            + resName
            + ") for fragment " + f));

异常确实是从这里抛出来的,原始是寻找container的时候找到了null,这里的f是参数传进来的Fragment,异常信息中报出的fragment就是当前参数f。通过调试,发现在真机和5.0以上的模拟器,mContainer.onFindViewById(f.mContainerId)都是正常获取到一个ViewGroup,唯独在4.4模拟器上面这句代码返回了null,看来问题就出来这里。继续调试进入源码findViewById(),代码如下:

@Nullable
public final View findViewById(@IdRes int id) 
    if (id < 0) 
        return null;
    
    return findViewTraversal(id);

当调试到这个位置时,id<0这个条件成立了,直接返回了null,看来问题是出现在id这个位置。当Fragment加载到ViewPager上面时由于寻找容器的id小于0直接返回null,最终导致抛出异常崩溃。

查看跟id相关的的代码逻辑:

mViewPager = new CustomViewPager(getContext(), null);
mViewPager.setId(mViewPager.hashCode());
mViewPager.setAdapter(mPagerAdapter);

问题的关键点,应该是找到了,viewPager的id是通过setId方法设置进去的,并且没有遵循这个api的使用规范,设置 R.id.xxx 这种方式来设置id。
Object.hashCode()方法在不同的版本中会有不同的表现,目前仅在4.4的模拟器上发现它会返回负数。

修复方案:
1. mViewPager.setId(R.id.pager); (推荐)
2. mViewPager.setId(Math.abs(mViewPager.hashCode()));

以上是关于java.lang.IllegalArgumentException: No view found for id 0xad7b9d70 (unknown) for fragment, 爬坑的主要内容,如果未能解决你的问题,请参考以下文章

IllegalArgumentException:此 NavController 未知导航目的地 xxx