ListView中出现Null附属(mAttachInfo == null)的情况

最近在我的项目中加入了自定义的TextAreaView,由于项目是在Dialog中只存在一个ListView.发现在此过程中第一条项目(也就是第一个View失去了mAttachInfo).从而导致View处于半瘫痪状态,也就是说View未被执行dispatchAttachedToWindow方法,从而导致View中的Handler为空指针.,也就导致了Post等一切利用View中Hanler进行视图绘制操作无效,除非调用父类进行重绘.

分析开始:

1. 首先我自定义的TextAreaView中有光标重绘的操作,是利用的View中的Post线程进行绘制,但是,我在View中的Post方法中打上Log后,发现确实调用了Post的方法,也就是说我自定义的View没有问题,鉴于第二条第三条View项目都处于正常状态,只有第一条处于瘫痪状态.将问题缩小到Post方法中.

2.使用反射获取Post方法执行时的测试条件if(mAttachInfo == null){...}发现mAttachInfo为空指针.由于我们都知道View在附属的过程中,是通过Parent往下递归附属的,所以我再次反射去查看View中的View.mParent变量是否也为Null,发现此Parent不为Null,由此得出,改View只是未被执行dispatchAttachedToWindow方法.

3.寻找ViewGroup中的执行过程,发现dispatchAttachedToWindow方法实在执行addViewInLayout方法中进行的,也就是说,ListView未对该View执行addViewInLayout,方法.

4.寻找ListView中的addViewInLayout方法.

    AbsListView.LayoutParams p = (AbsListView.LayoutParams) child.getLayoutParams();
        if (p == null) {
            p = new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT, 0);
        }
        p.viewType = mAdapter.getItemViewType(position);

        if ((recycled && !p.forceAdd) || (p.recycledHeaderFooter &&
                p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER)) {
            attachViewToParent(child, flowDown ? -1 : 0, p);
        } else {
            p.forceAdd = false;
            if (p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {
                p.recycledHeaderFooter = true;
            }
            addViewInLayout(child, flowDown ? -1 : 0, p, true);
        }
与此可见一定是第一条if语句被执行了,由于我并没有设置Header所有if语句第二个条件不可能通过,只有第一个

由此发现recycled为true,也就是说我的第一条View在返回知道直接被ListView进行了recyle,并且我的LayoutParams中的forceAdd==false.或者LayoutParams == null,

5.我发现ListView在测量过程中如下执行:


        mItemCount = mAdapter == null ? 0 : mAdapter.getCount();
        if (mItemCount > 0 && (widthMode == MeasureSpec.UNSPECIFIED ||
                heightMode == MeasureSpec.UNSPECIFIED)) {
            final View child = obtainView(0, mIsScrap);

            measureScrapChild(child, 0, widthMeasureSpec);

            childWidth = child.getMeasuredWidth();
            childHeight = child.getMeasuredHeight();
            childState = combineMeasuredStates(childState, child.getMeasuredState());

            if (recycleOnMeasure() && mRecycler.shouldRecycleViewType(
                    ((LayoutParams) child.getLayoutParams()).viewType)) {
                mRecycler.addScrapView(child, -1);
            }
        }
也就是说第一条项目会被特殊处理,直接添加到mRecucler中,从而导致recyle为true,但是在measureScrapChild方法中会进行如下

    private void measureScrapChild(View child, int position, int widthMeasureSpec) {
        LayoutParams p = (LayoutParams) child.getLayoutParams();
        if (p == null) {
            p = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT, 0);
            child.setLayoutParams(p);
        }
        p.viewType = mAdapter.getItemViewType(position);
        p.forceAdd = true;
也就是说p.forceAdd被设置为true,由此第4个中的if条件是不可能被执行的,除非p.forceAdd 被赋值为 false.

6.我已经说过没有被执行addViewInLayout,所以p,forceAdd被赋值为false,是不可能在ListView中进行的,那么只有一个原因了,那就是我们重新设置了该项目的LayoutParames,这样LayoutParames中的forceAdd才能为false.

7.我检测我的方法发现,我在getView中由于马虎,竟然将LayoutParames进行了多次设置,也就是说不管是不是View复用,我都new一个新的LayoutParams添加到View中,从而导致了forceAdd为false的情况.将setLayoutParames(new LayoutParames)设置在convertView == null的情况下,问题解决


Node:我又发现,此问题只会发生在Dialog模式下,因为我在Framget中的ListView如此设置并没有出现任何问题,这个问题保留一下,再去详细的查找原因吧.


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值