listView重用机制

本文引用http://www.linuxidc.com/Linux/2015-02/113878.htm

概述

ListView 是继承AbListView,AbListView是所有列表类控件的基类。

ListView的数据加载

在ListView数据加载中最关键的一个函数就是makeAndAddView(),这个函数的作用就获得一个ChildView并把该ChildView添加到List中,具体见源码分析:

/**
 * Obtain the view and add it to our list of children. The view can be made
 * fresh, converted from an unused view, or used as is if it was in the
 * recycle bin.
 **/

private View makeAndAddView(int position, int y, boolean flow, int childrenLeft,
    boolean selected) {
View child;//即ChildView

//如果数据没有发生改变
if (!mDataChanged) {
    //优先从循环器中获取该位置的视图
    // Try to use an existing view for this position
    child = mRecycler.getActiveView(position);
    if (child != null) {
        // Found it -- we're using an existing child
        //如果找到了就直接添加到List中
        // This just needs to be positioned
        setupChild(child, position, y, flow, childrenLeft, selected, true);

        return child;
    }
}

    //如果数据发生了改变,则在该位置上新建一个视图,或者如果可能的话转换一个已经没有用的视图(可能是当整个ListView其他位置发生了变化,但是该位置的ChildView并未发生任何变化)
    // Make a new view for this position, or convert an unused view if possible
    child = obtainView(position, mIsScrap);

    // This needs to be positioned and measured
    setupChild(child, position, y, flow, childrenLeft, selected, mIsScrap[0]);

    //返回该childView
    return child;
}

ListView的缓存机制

当ListView发生滑动操作时,若干已经加载的ChildView会被因滑动而被暂时隐藏掉,为了避免下次显示再重新加载,这时ListView的缓存机制就会被触发,即运行layoutChildren()函数(其实任何触碰事件都会触发,即onTouchEvent() )

那么ListView的缓存机制是依靠什么来缓存的呢?答案就是AbListView中 的内部类RecycleBin。

RecycleBin类

关于RecycleBin的具体作用,源码中的注释已经解释的非常清楚了,在此就不在赘述。

*RecycleBin有两大存储类型:ActiveViews 和 ScrapViews
*ActiveView 是呈现在屏幕上的view,ScrapViews就是滑动时隐藏的view。

/**
* The RecycleBin facilitates reuse of views across layouts. The RecycleBin has two levels of
* storage: ActiveViews and ScrapViews. ActiveViews are those views which were onscreen at the
* start of a layout. By construction, they are displaying current information. At the end of
* layout, all views in ActiveViews are demoted to ScrapViews. ScrapViews are old views that
* could potentially be used by the adapter to avoid allocating views unnecessarily.
 *... ...
 */

当需要缓存ActiveViews时会调用fillActiveViews()函数,该函数会把ListView中的所有ActiveViews 一次性都缓存起来。

/**
 * Fill ActiveViews with all of the children of the AbsListView.
 * ... ...
 */
void fillActiveViews(int childCount, int firstActivePosition) {
    if (mActiveViews.length < childCount) {
        mActiveViews = new View[childCount];
    }
    mFirstActivePosition = firstActivePosition;

    //noinspection MismatchedReadAndWriteOfArray
    final View[] activeViews = mActiveViews;
    ... ...
}

而对于ScrapViews则是调用的addScrapView()函数。

/**
 * Puts a view into the list of scrap views.
 * <p>
 * If the list data hasn't changed or the adapter has stable IDs, views
 * with transient state will be preserved for later retrieval.
 *
 * @param scrap The view to add
 * @param position The view's position within its parent
 */
void addScrapView(View scrap, int position) {
... ...
// Don't scrap views that have transient state.
    final boolean scrapHasTransientState = scrap.hasTransientState();
    if (scrapHasTransientState) {
    //Transient状态
    ... ...
    }else{
    //scrap状态
    ... ...
    }
    ... ...
}

该函数中又分为两个不同的level,一个是transient瞬时态,另一个就是一般的普通态,关于这两个状态的区分我个人的想法是为了更加快速的获取ScrapViews,因为处于瞬时状态的view最有可能是接下来将要在界面上显示的View,毕竟你向上或向下滑动列表时目的就是这个,这一点在obtainView()函数中得到了体现:

View obtainView(int position, boolean[] isScrap) {
... ...
//优先获取TransientStateView
scrapView = mRecycler.getTransientStateView(position);
if (scrapView == null) {
    scrapView = mRecycler.getScrapView(position);
}
... ...
}

还有一个比较重要的函数就是scrapActiveViews()函数,它的作用是将目前所有的ActiveViews降级为ScrapViews,并将之前的所有ScrapViews清除。该函数在每次调用layoutChildern()函数时必定会被调用执行,目的就是为清空所有当前的ActiveViews,为新产生的ActiveViews做好准备。

View obtainView(int position, boolean[] isScrap) {
    isScrap[0] = false;
    View scrapView;
    //优先获取TransientStateView
    scrapView = mRecycler.getTransientStateView(position);
    if (scrapView != null) {
        return scrapView;
    }
    scrapView = mRecycler.getScrapView(position);
    View child;
    if (scrapView != null) {
        child = mAdapter.getView(position, scrapView, this);
        ...
        if (child != scrapView) {
            mRecycler.addScrapView(scrapView, position);
            ...
    } else {
        child = mAdapter.getView(position, null, this);
       ....
    }
    ...
    ...
    return child;
}


/**
 * Move all views remaining in mActiveViews to mScrapViews.
 */
void scrapActiveViews() {
... ...
//该函数确保mScrapViews的大小不会超过mActiveViews
pruneScrapViews();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值