美文网首页Android日常
android 解决 java.lang.IllegalStat

android 解决 java.lang.IllegalStat

作者: 盗版三弟 | 来源:发表于2020-04-07 16:42 被阅读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);
            }
        }
    

    相关文章

      网友评论

        本文标题:android 解决 java.lang.IllegalStat

        本文链接:https://www.haomeiwen.com/subject/pyenphtx.html