Android日常

android 解决 java.lang.IllegalStat

2020-04-07  本文已影响0人  盗版三弟

报错信息:

Caused by:
 java.lang.IllegalStateException:ViewStub must have a non-null ViewGroup viewParent
 android.view.ViewStub.inflate(ViewStub.java:318)

先给结论:viewStub.inflate()或者setVisibility(int)只能调用一次,多次调用了就会报该错误;通过设置OnInflateListener可以记录一个viewstub是否已经inflate过,避免多次调用

分析原因

查看viewStub.inflate方法

  public View inflate() {
        final ViewParent viewParent = getParent();
        if (viewParent != null && viewParent instanceof ViewGroup) {
            //省略...
        } else {
        //报错了情况走到了这里 说明viewparent=null了
            throw new IllegalStateException("ViewStub must have a non-null ViewGroup viewParent");
        }
    }

正常的排查思路是看 viewParent是怎么赋值的,然后调查inflate之前viewParent为什么为空;debug复现时很容易发现 ,异常是在第二次重复调用ViewStub. inflate()时出现的;所以我们看下inflate做了哪些事情

                final ViewGroup parent = (ViewGroup) viewParent;
                final View view = inflateViewNoAdd(parent);//1
                replaceSelfWithView(view, parent);//2

                mInflatedViewRef = new WeakReference<>(view);
                if (mInflateListener != null) {
//设置了OnInflateListener 就可以记录该stub是否已经inflate过
                    mInflateListener.onInflate(this, view);
                }
                return view;

标注1处源码如下:可见是将ViewStub中layout中的布局填充后作为view返回,源码如下

 private View inflateViewNoAdd(ViewGroup parent) {
        final LayoutInflater factory;
        if (mInflater != null) {
            factory = mInflater;
        } else {
            factory = LayoutInflater.from(mContext);
        }
        final View view = factory.inflate(mLayoutResource, parent, false);
        if (mInflatedId != NO_ID) {
            view.setId(mInflatedId);//这里对应xml中android:inflatedId
        }
        return view;
    }

标记2处replaceSelfWithView()方法名很准确概括了的作用:用填充的view替换viewStub加入到viewStub的父布局中,viewStub的viewParent就是在移除的时候被设置成了null;所以viewStub.inflate()执行一次后,该view已被从父布局中移除,第二次调用就会报异常

    private void replaceSelfWithView(View view, ViewGroup parent) {
        final int index = parent.indexOfChild(this);
       //3这里将viewstub的parentView设置为了null;
        parent.removeViewInLayout(this);
        final ViewGroup.LayoutParams layoutParams = getLayoutParams();
        if (layoutParams != null) {
            parent.addView(view, index, layoutParams);
        } else {
            parent.addView(view, index);
        }
    }
上一篇下一篇

猜你喜欢

热点阅读