Android ListView onScroll NullPointerException ListView滚动崩溃

当我们使用ListView,想获取第一个ListItem的高度和宽度的时候,我们需要监听ListView的滚动。从我所犯的错误说起。我有一个ListView,里面有很多数据,我想设置一个固定的头部,然后需要的是获取第一个ListItem的位置,想知道位置,当然先要获得这个view,因为是动态的,需要在onScroll中获取,所以变成这以下:


public class TestListView extends ListFragment implements AbsListView.OnScrollListener {

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {

    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        //获取第一个可见的view
        View firstView = view.getChildAt(firstVisibleItem);
        Log.d("hehe", "firtsview height is:" + firstView.getHeight() + ",width is:" + firstView.getWidth());
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        getListView().setOnScrollListener(this);
    }
}

别高兴太早,这个代码根本跑不起来,一运行就会崩溃抛出异常:NullPointerException ,没错,就是firstView抛出来的。按照逻辑,onScroll中的View就是ListView,firstVisibleItem就是可见的第一个item,所以怎么都看不出为什么取不到View。仔细翻看文档,OnScrollListener是这么解释的:

/**
         * Callback method to be invoked when the list or grid has been scrolled. This will be
         * called after the scroll has completed
         * @param view The view whose scroll state is being reported
         * @param firstVisibleItem the index of the first visible cell (ignore if
         *        visibleItemCount == 0)
         * @param visibleItemCount the number of visible cells
         * @param totalItemCount the number of items in the list adaptor
         */
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
                int totalItemCount);

firstVisibleItem会忽略visibleitemcount是零的情况,因为刚开始初始化的时候,visibleitemCount还是为零的,所以view.getChildAt 获取到的就是null,说白了,view还是null,怎么去得到呢?所以像下面修改:

@Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        if (visibleItemCount == 0) {
            return;
        }
        //获取第一个可见的view
        View firstView = view.getChildAt(firstVisibleItem);
        Log.d("hehe", "firtsview height is:" + firstView.getHeight() + ",width is:" + firstView.getWidth());
    }

恩,忽略掉当count还为0的情况,这时能运行起来了。

但是,别高兴太早,只要往下滑超过一屏之后,你还是会发现又崩溃了,还是同样的错误,NullPointerException,又是空指针异常。。。搞了一个晚上,我也崩溃了。。。

到最后通过不断调试,发现了一个秘密:onScroll方法中的参数view根本就只是可见的item,不可见的item已经被回收了。这先要理解ListView的机制,它是这样的:当移出屏幕外的item的view是会重新回收利用的,所以ListView中的实际的View只有可见的,不可见的完全被回收了,详情见这里:http://android.amberfog.com/?p=296

参数view所表示的ListView,并不是表示ListView中有item一样多的View,它只有当前可见的。所以,ListView中第一个就是0,而不是firstVisibleItem的值,代码改成如下就可以正常运行了:

@Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        if (visibleItemCount == 0) {
            return;
        }
        //获取第一个可见的view
        View firstView = view.getChildAt(0);
        Log.d("hehe", "firtsview height is:" + firstView.getHeight() + ",width is:" + firstView.getWidth());
    }

PS:这就是纠结一个晚上所明白的,代价有点高啊!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值