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 MyFragment{ad792440 #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()));

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值