AbsListView中item重用机制

AbsListView中item重用机制
ListView是一个非常神奇的功能,我相信大家应该都体验过,即使在ListView中加载非常非常多的数据,比如达到成百上千条甚至更多,ListView都不会发生OOM或者崩溃,而且随着我们手指滑动来浏览更多数据时,程序所占用的内存竟然都不会跟着增长。要达到这种效果,一定是重用了item,将划出屏幕的item作为新item,添加到屏幕中,从而达到了内存稳定的效果。

原理图


RecycleBin机制
RecycleBin为AbsListView中的一个内部类。主要作用就是实现Item的缓存,将废弃的item添加到缓存中,为以后出现的item重用,使得ListView能够实现成百上千条数据都不会OOM最重要的一个原因。

核心方法介绍
class  RecycleBin {

    /**
     * 当前有效的item的View
     */

    private  View[] mActiveViews  =  new  View[ 0];

    /**
     * 被废弃的item的View
     */

    private  ArrayList<View>[] mScrapViews;

    /**
     * RecycleBin当中使用mActiveViews这个数组来存储View,调用这个方法后就会根据传入的参数来将ListView中的指定元素
     * 存储到mActiveViews数组当中。
     * @param childCount 表示要存储的view的数量
     * @param firstActivePosition AbsListView中第一个可见元素的position值
     */

    void  fillActiveViews( int  childCountint  firstActivePosition);

    /**
     * 与fillActiveViews()是对应的,用于从mActiveViews数组当中获取数据。需要注意的是,mActiveViews当中所存储的
     * View,一旦被获取了之后就会从mActiveViews当中移除,下次获取同样位置的View将会返回null,也就是说mActiveViews
     * 不能被重复利用。
     * @param position 元素在ListView当中的位置
     * @return 返回当前显示的item
     */

    View  getActiveView( int  position);

    /**
     * 用于将一个废弃的View进行缓存,该方法接收一个View参数,当有某个View确定要废弃掉的时候(比如滚动出了屏幕),
     * 就应该调用这个方法来对View进行缓存
     * @param scrap 被废弃的View
     */

    void  addScrapView( View  scrap);

    /**
     * 用于从废弃缓存中取出一个View
     * @param position 位置
     * @return 废弃缓存中的View
     */

    View  getScrapView( int  position);
}

AbsListView回收过程分析
分析回收过程
主要分三步,来讲解AbsListView中item的回收,如下:
     1. 首次调用Layout,主要分析创建item的过程  
     2. 再次调用Layout,主要分析将item回收到mActiviyView缓存中,并重用过程 
     3.AbsListView滑动分析,主要分析将item的回收到scrapview中并重用过程

首次调用Layout
函数调用流程
onLayout()  AbsListView中统一实现布局方法,并且调用子类layoutChildren()
     —>layoutChildren()  ListView与GridView中各自实现视图布局,这里以ListView为例
     —>RecycleBin.fillActiveViews() 调用此方法是为了将ListView的子View进行缓存的,但当前ListView为空,因此这一行暂时还起不了任何作用
     —>fillFromTop() 直接调用fillDown()方法,没有做什么操作
     —>fillDown() 内部while循环构造item,while循环单单刷新屏幕可见部分。构造item,使用makeAndAddView()方法
     —>makeAndAddView() 由于当前RecycleBin.mActiveViews为空,所以调用obtainView声明item
     —>obtainView() 由于当前RecycleBin.mScrapViews为空,所以调用Adapter.getView()构建item。
     —>Adapter.getView() 适配器获取item 
此次调用,主要完成了AbsListView可见部分的视图创建。RecycleBin的缓存操作都还没有来得及实现。

再次调用Layout
函数调用流程
onLayout()  AbsListView中统一实现布局方法调用,并且调用子类layoutChildren()
     —>layoutChildren()  ListView与GridView中各自实现视图布局,这里以ListView为例
     —>RecycleBin.fillActiveViews() 首次调用Layout时,已经创建了item,调用此方法将当前item缓存到RecycleBin.mActiveViews中
     —>fillSpecific() 此函数主要负责填充ListView中的视图,并且调用fillDown()与fillUp()继续填充,最终还是调用makeAndAddView()方法
     —>makeAndAddView() 当前RecycleBin.mActiveViews已经在layoutChildren()中填充了,所以可以直接调用RecycleBin.getActivityView()获取,并设置位置
此次调用,主要展示了AbsListView可见部分的视图重用。RecycleBin中的RecycleBin.mActiveViews已经构建完成了,所以可以调用RecycleBin.getActivityView()获取缓存,并复用。

AbsListView滑动分析
onTouchEvent()  触摸事件回调接口,判断当前触摸类型,分发事件。这里主要是滑动分析,所有主要看onTouchMove()方法
     —>onTouchMove()  主要是对滑动事件的逻辑处理,最终调用scrollIfNeeded()方法进行滑动处理
     —>scrollIfNeeded()  处理滚动操作,最终调用trackMotionScroll()方法
     —>trackMotionScroll() 此方法做了最关键的操作,就是将已经滑出屏幕的item,添加到了RecycleBin.mScrapViews中,方便复用。并调用fillGap()填充布局
     —>fillGap() 此方法为滑动后空出来的位置填充item视图,最终调用makeAndAddView()方法获取item
     —>makeAndAddView() 由于RecycleBin.mActiveViews中不存在新位置的item的缓存,所以调用obtainView声明item
     —>obtainView() 由于trackMotionScroll()中将移出的item填充到了RecycleBin.mScrapViews缓存中,所以复用RecycleBin.mScrapViews中的item来填充新item
此次调用,主要展示了AbsListView中真正的item的视图重用。将从屏幕移除的item添加到RecycleBin.mScrapViews中,再从RecycleBin.mScrapViews中调用废弃的item并复用。

参考
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值