Android ListView

1.Listview

Listview是用来显示大量数据的控件,且不会因为展示大量数据而出现内存溢出的现象,原因是它的缓存机制保证了内存的合理使用。

首先看一下ListView的继承结构:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5a2f6Iqz6Iqz,size_17,color_FFFFFF,t_70,g_se,x_16

ListView直接继承自AbsListView,而AbsListView有两个子实现类,一个是ListView,一个是GridView,从这一点就可以看出来,ListView和GridView在工作原理和实现上都是有很多共同点的。然后AbsListView继承自AdapterView,AdapterView继承自ViewGroup。

 

2.RecycleBin机制

RecycleBin是ListView缓存的核心机制,它是ListView能够实现成百上千条数据都不会OOM最重要的原因。

RecycleBin是AbsListView的一个内部类,所有继承自AbsListView的子类,也就是ListView和GridView,都可以使用这个机制。

class RecycleBin {

    private RecyclerListener mRecyclerListener;

    private int mFirstActivePosition;

    //mActiveViews存放正在显示在屏幕上的view ,从显示在屏幕上的第一个view到最后一个view

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

    //mScrapViews存放可以由适配器用作convert view的view,是一个数组,数组的每个元素类型为ArrayList<View>

    private ArrayList<View>[] mScrapViews;

    private int mViewTypeCount;       

    //mCurrentScrap是mScrapViews的第0个元素,当view种类数量为1时存放废弃view

    private ArrayList<View> mCurrentScrap;      

    //Adapter中可以重写getViewTypeCount方法来表示ListView中有几种类型的数据项,而setViewTypeCount()方法就是为每种类型的数据项都单独启用一个RecycleBin缓存机制

    public void setViewTypeCount(int viewTypeCount) {

        if (viewTypeCount < 1) {

            throw new IllegalArgumentException( "Can't have a viewTypeCount < 1");

        }

        ArrayList<View>[] scrapViews = new ArrayList[viewTypeCount];

        for (int i = 0; i < viewTypeCount; i++) {

            scrapViews[i] = new ArrayList<View>();

        }

        mViewTypeCount = viewTypeCount;

        mCurrentScrap = scrapViews[0];

        mScrapViews = scrapViews;

    }        

    // fillActiveViews()接收两个参数,第一个参数表示mActiveViews数组最小要保存的View数量,第二个参数表示ListView中第一个可见元素的position值。 根据传入的参数将ListView中的指定元素存储到mActiveViews数组当中

    void fillActiveViews(int childCount, int firstActivePosition) {

        if (mActiveViews.length < childCount) {

            mActiveViews = new View[childCount];

        }

        mFirstActivePosition = firstActivePosition;

        final View[] activeViews = mActiveViews;

        for (int i = 0; i < childCount; i++) {

            View child = getChildAt(i);

            AbsListView.LayoutParams lp = (AbsListView.LayoutParams) child.getLayoutParams();

            if (lp != null && lp.viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {

                activeViews[i] = child;

                lp.scrappedFromPosition = firstActivePosition + i;

            }

        }

    }        

    //getActiveView()方法用于从mActiveViews数组中取出特定元素。该方法接收一个position参数,表示元素在ListView当中的位置,方法内部会自动将position值转换成mActiveViews数组对应的下标值。mActiveViews当中所存储的View,一旦被获取之后就会从mActiveViews当中移除,下次获取同样位置的View将会返回null,也就是说mActiveViews不能被重复利用。如果在mActiveViews数组中没有找到,则返回null

    View getActiveView(int position) {

        int index = position - mFirstActivePosition;

        final View[] activeViews = mActiveViews;

        if (index >=0 && index < activeViews.length){

            final View match = activeViews[index];

            activeViews[index] = null;

            return match;

        }

        return null;

    }        

    //getScrapView()用于从废弃缓存中取出一个View。这些废弃缓存中的View是没有顺序可言的,因此getScrapView()方法中的算法非常简单,就是直接从mCurrentScrap当中获取尾部的一个scrap view进行返回

    View getScrapView(int position) {

        final int whichScrap = mAdapter.getItemViewType(position);

        if (whichScrap < 0) {

            return null;

        }

        if (mViewTypeCount == 1) {

            return retrieveFromScrap(mCurrentScrap, position);

        } else if (whichScrap < mScrapViews.length){

            return retrieveFromScrap( mScrapViews[whichScrap], position);

        }

        return null;

    }

    private View retrieveFromScrap( ArrayList<View> scrapViews, int position) {

        final int size = scrapViews.size();

        if(size > 0) {

            for(int i = size - 1; i >= 0; i--) {

                final View view = scrapViews.get(i);

                final AbsListView.LayoutParams params = (AbsListView.LayoutParams) view.getLayoutParams();

                if(mAdapterHasStableIds) {

                    final long id = mAdapter.getItemId( position);

                    if(id == params.itemId){

                        return scrapViews.remove(i);

                    }

                } else if(params.scrapedFromPosition == position) {

                    final View scrap = scrapViews.remove(i);

                    clearScrapForRebind(scrap);

                    return scrap;

                }

            }

            final View scrap = scrapViews.remove( size - 1);

            clearScrapForRebind(scrap);

            return scrap;

        }

        return null;

    }

    //addScrapView()用于将一个废弃的View进行缓存。该方法接收一个View参数,当有某个View确定要废弃掉的时候(比如滚动出了屏幕),应该调用这个方法来对View进行缓存。当view类型为1时则用mCurrentScrap存储废弃view,否则使用mScrapViews添加废弃view

    void addScrapView(View scrap, int position) {

        final AbsListView.LayoutParams lp = (AbsListView.LayoutParams) scrap.getLayoutParams();

        if (lp == null) {

            return;

        }

        lp.scrappedFromPosition = position;

        final int viewType = lp.viewType;

        if (!shouldRecycleViewType(viewType)) {

            if (viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {

                getSkippedScrap().add(scrap);

            }

            return;

        }

        if (scrapHasTransientState) {

           ……

        } else {

            if (mViewTypeCount == 1) {

                mCurrentScrap.add(scrap);

            } else {

                mScrapViews[viewType].add(scrap);

            }

           

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值