android ListView中view的复用源码分析

来源:互联网 发布:mac的无线设置路由器 编辑:程序博客网 时间:2024/06/07 14:48

下面简要分析android中BaseAdapter的getView()方法中convertView的来源(API19):

ListView一定在用户卷动列表的时候调用了adapter的getView()方法来获取要显示的新的项目的view对象。

然而ListView类的源代码中没有这个调用,所以应当是在其父类AbsListView中调用过,

我们在AbsListView类中查找adapter的getView()方法的调用作为追踪的起点:

1 AbsListView的obtainView()方法

//该方法调用了adaptergetView()方法

View obtainView(int position, boolean[] isScrap) {

     ........................

         //scrapView是从mRecycler中取出的View对象

        View scrapView;

 

        scrapView =mRecycler.getTransientStateView(position);

        if (scrapView == null) {

          //recycler中取出scrapView对象用于复用

            scrapView = mRecycler.getScrapView(position);

        }

 

        View child;

         //如果recycler中有可用的scrapView,就将scrapView传给adaptergetView()方法去复用

        if (scrapView != null) {

              //调用adaptergetView()方法,注意,scrapView就是getView()方法传入的形参convertView

            child =mAdapter.getView(position, scrapView, this);

              .........................

              //如果adaptergetView()方法返回的View不是刚才传入的scrapView

              //说明用户没有复用scrapView,它被重新放回到mRecylcler

            if (child != scrapView) {

               mRecycler.addScrapView(scrapView, position);

              ...........................               

            }

        }

         //如果recycler中没有任何view可以拿出来传给adaptergetView()方法去复用,那就传null

         else {

            child = mAdapter.getView(position, null, this);

              .......................

        }

        return child;

    }

上面的源代码明确表示,用于复用的scrapView是调用mRecycler的getScrapView()方法得到的

而且不用的scrapView是调用mRecycler的addScrapView()方法放回mRecycler的

所以我们来看RecycleBin类和它的getScrapView()方法:

2 RecycleBin和它的getScrapView()方法

//上文中的mRecyclerRecycleBin类的一个对象

final RecycleBin mRecycler = new RecycleBin();

class RecycleBin{

         ..................

         /** 原版注释:

         * Views that were on screen at thestart of layout. This array is populated at the start of

         * layout, and at the end of layout allview in mActiveViews are moved to mScrapViews.

         * Views in mActiveViews represent acontiguous range of Views, with position of the first

         * view store in mFirstActivePosition.

         */

         /**原版注释的翻译:

         * mActiveViews:

         *布局生成伊始就显示在屏幕上的Views.这个数组在布局生成时就初始化,

         * 最终所有在mActiveViews数组中的View都会被移动到mScrapViews

          * /

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

          /** 原版注释:

        * Unsorted views that can be used by the adapter as a convert view.

        */

         /** 原版注释的翻译:

         * mScrapViews

         * 未排序的views,这些view可以被adapter用作复用

         */

        privateArrayList<View>[] mScrapViews;

 

       .....................................

       

        /** 原版注释:

        * @return A view from the ScrapViews collection. These are unordered.

        */

         /** 原版注释的翻译:

         * ScarpViews集合中返回一个View。返回的View是无序的。

         */

       View getScrapView(int position) {

           if (mViewTypeCount == 1) {

                return retrieveFromScrap(mCurrentScrap, position);

           } else {

                int whichScrap =mAdapter.getItemViewType(position);

                if (whichScrap >= 0&& whichScrap < mScrapViews.length) {

                    return retrieveFromScrap(mScrapViews[whichScrap],position);

                }

           }

           return null;

       }

       ..............................

}

看到这,我们发现RecycleBin类的getScrapView()方法实际上调用的是retrieveFromScrap()方法来获得ScrapView

而这个方法不是定义在RecycleBin类中的,是定义在AbsListView类中的一个静态方法:

3 AbsListView的retrieveFromScrap()方法

//RecycleBingetScrapView()方法将RecycleBin类中的存储scrapViewsArrayList传给下面的方法

//retrieveFromScrap()方法返回一个ViewgetScrapView()方法,进而传给adaptergetView()方法作为复用的view

static View retrieveFromScrap(ArrayList<View> scrapViews, intposition) {

        int size = scrapViews.size();

        //如果scrapViewarrayList中存储有scrapView

        if (size > 0) {

            //遍历arrayList中的所有scrapView

           //去掉对应同一position的重复的scrapView

           //如果刚好请求复用的positionscrapViewarrayList中某个scrapViewposition相同

           //则返回这个scrapView

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

                View view = scrapViews.get(i);

                if (((AbsListView.LayoutParams)view.getLayoutParams())

                        .scrappedFromPosition== position) {

                    scrapViews.remove(i);

                    return view;

                }

            }

            //不巧没有对应同一positionscrapView,就将scrapViewarrayList的最后一项返回

            -return scrapViews.remove(size  1);

         //如果scrapViewarrayList中没有任何scrapView,返回null

        } else {

            return null;

        }

    }

4 总结

ListView中的RecycleBin内部类保存了一个View[]数组mActiveViews,用来保存屏幕上正在显示的所有View

还保存了一个ArrayList<View>集合mScrapViews,用来保存所有滑出屏幕等待复用的View。

当用户滑动屏幕时,ListView会从mActiveViews中将滑出屏幕的view加入mScrapViews

并从后者取出view传给adapter的getView()方法供其复用


0 0