`
daojin
  • 浏览: 690369 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

Android面试题目之(13) ListView的设计原理

 
阅读更多
1.ListView的目标

ListView希望通过复用看不见的View来达到目的。其中最最重要的就是这个

2.RecycleBin--回收站.

回收站并不是垃圾站。
    最重要的是两个成员变量 mScrapViews 和mActiveViews, mScrapViews 表示回收站的View. mActiveViews表示激活的View,激活的View是可以直接拿来显示的,不想要重新调用getView填充数据。激活的View(mActiveViews)和废弃的View(mScrapViews) 不同,激活的View不想要调用getView填充数据,而废弃的View需要。

      
 /**
         * Unsorted views that can be used by the adapter as a convert view.
         */
        private ArrayList<View>[] mScrapViews;

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


  看不见的View都会放进这里面。主要是通过以下方法 addScrapView 加进去的
   
    /**
         * Put a view into the ScapViews list. These views are unordered.
         *
         * @param scrap The view to add
         */
        void addScrapView(View scrap, int position) {
            AbsListView.LayoutParams lp = (AbsListView.LayoutParams) scrap.getLayoutParams();
            if (lp == null) {
                return;
            }

            // Don't put header or footer views or views that should be ignored
            // into the scrap heap
            int viewType = lp.viewType;
            if (!shouldRecycleViewType(viewType)) {
                if (viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {
                    removeDetachedView(scrap, false);
                }
                return;
            }

            lp.scrappedFromPosition = position;

            if (mViewTypeCount == 1) {
                scrap.dispatchStartTemporaryDetach();
                mCurrentScrap.add(scrap);
            } else {
                scrap.dispatchStartTemporaryDetach();
                mScrapViews[viewType].add(scrap);
            }

            if (mRecyclerListener != null) {
                mRecyclerListener.onMovedToScrapHeap(scrap);
            }
        }


3.回收站算法

makeAndAddView 这个方法显示了回收站的使用算法。如果没有dadachange,那么就直接从getActiveView 方法取得那个View,如果成功,就调整其位置。如果datachange,就需要重新绑定数据到这个View上。这里的 重新绑定数据 方法obtainView 同时考虑是否使用回收站的View.

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


        if (!mDataChanged) {
            // Try to use an existing view for this position
            child = mRecycler.getActiveView(position);
            if (child != null) {
                if (ViewDebug.TRACE_RECYCLER) {
                    ViewDebug.trace(child, ViewDebug.RecyclerTraceType.RECYCLE_FROM_ACTIVE_HEAP,
                            position, getChildCount());
                }

                // Found it -- we're using an existing child
                // This just needs to be positioned
                setupChild(child, position, y, flow, childrenLeft, selected, true);

                return child;
            }
        }

        // 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]);

        return child;
}



4.通过ObtainView方法绑定数据

其实也很简单。主要任务是复用mScrapViews。

   
View obtainView(int position, boolean[] isScrap) {
        isScrap[0] = false;
        View scrapView;

        scrapView = mRecycler.getScrapView(position);

        View child;
        if (scrapView != null) {
            if (ViewDebug.TRACE_RECYCLER) {
                ViewDebug.trace(scrapView, ViewDebug.RecyclerTraceType.RECYCLE_FROM_SCRAP_HEAP,
                        position, -1);
            }

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

            if (ViewDebug.TRACE_RECYCLER) {
                ViewDebug.trace(child, ViewDebug.RecyclerTraceType.BIND_VIEW,
                        position, getChildCount());
            }

            if (child != scrapView) {
                mRecycler.addScrapView(scrapView, position);
                if (mCacheColorHint != 0) {
                    child.setDrawingCacheBackgroundColor(mCacheColorHint);
                }
                if (ViewDebug.TRACE_RECYCLER) {
                    ViewDebug.trace(scrapView, ViewDebug.RecyclerTraceType.MOVE_TO_SCRAP_HEAP,
                            position, -1);
                }
            } else {
                isScrap[0] = true;
                child.dispatchFinishTemporaryDetach();
            }
        } else {
            child = mAdapter.getView(position, null, this);
            if (mCacheColorHint != 0) {
                child.setDrawingCacheBackgroundColor(mCacheColorHint);
            }
            if (ViewDebug.TRACE_RECYCLER) {
                ViewDebug.trace(child, ViewDebug.RecyclerTraceType.NEW_VIEW,
                        position, getChildCount());
            }
        }

        return child;
    }

5.布局listView

fillDown 方法用得最多,其目的就是从pos这个index和nextTop这个View top坐标,向下填充Views直到底部。

    /**
     * Fills the list from pos down to the end of the list view.
     *
     * @param pos The first position to put in the list
     *
     * @param nextTop The location where the top of the item associated with pos
     *        should be drawn
     *
     * @return The view that is currently selected, if it happens to be in the
     *         range that we draw.
     */
    private View fillDown(int pos, int nextTop) {
        View selectedView = null;

        int end = (mBottom - mTop);
        if ((mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {
            end -= mListPadding.bottom;
        }

        while (nextTop < end && pos < mItemCount) {
            // is this the selected item?
            boolean selected = pos == mSelectedPosition;
            View child = makeAndAddView(pos, nextTop, true, mListPadding.left, selected);

            nextTop = child.getBottom() + mDividerHeight;
            if (selected) {
                selectedView = child;
            }
            pos++;
        }

        return selectedView;
    }

6.触发fillDown的切入点

layoutChildren
trackMotionScroll


7.不得不说的LayoutParams
    /**
     * AbsListView extends LayoutParams to provide a place to hold the view type.
     */
    public static class LayoutParams extends ViewGroup.LayoutParams {
        /**
         * View type for this view, as returned by
         * {@link android.widget.Adapter#getItemViewType(int) }
         */
        @ViewDebug.ExportedProperty(category = "list", mapping = {
            @ViewDebug.IntToString(from = ITEM_VIEW_TYPE_IGNORE, to = "ITEM_VIEW_TYPE_IGNORE"),
            @ViewDebug.IntToString(from = ITEM_VIEW_TYPE_HEADER_OR_FOOTER, to = "ITEM_VIEW_TYPE_HEADER_OR_FOOTER")
        })
        int viewType;

        /**
         * When this boolean is set, the view has been added to the AbsListView
         * at least once. It is used to know whether headers/footers have already
         * been added to the list view and whether they should be treated as
         * recycled views or not.
         */
        @ViewDebug.ExportedProperty(category = "list")
        boolean recycledHeaderFooter;

        /**
         * When an AbsListView is measured with an AT_MOST measure spec, it needs
         * to obtain children views to measure itself. When doing so, the children
         * are not attached to the window, but put in the recycler which assumes
         * they've been attached before. Setting this flag will force the reused
         * view to be attached to the window rather than just attached to the
         * parent.
         */
        @ViewDebug.ExportedProperty(category = "list")
        boolean forceAdd;

        /**
         * The position the view was removed from when pulled out of the
         * scrap heap.
         * @hide
         */
        int scrappedFromPosition;

        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
        }

        public LayoutParams(int w, int h) {
            super(w, h);
        }

        public LayoutParams(int w, int h, int viewType) {
            super(w, h);
            this.viewType = viewType;
        }

        public LayoutParams(ViewGroup.LayoutParams source) {
            super(source);
        }
    }


8.提高布局性能的函数 offsetLeftAndRight和 offsetTopAndBottom

在setupChild函数 中可以看到如下两行
      if (needToMeasure) {
            final int childRight = childrenLeft + w;
            final int childBottom = childTop + h;
            child.layout(childrenLeft, childTop, childRight, childBottom);
        } else {
            child.offsetLeftAndRight(childrenLeft - child.getLeft());
            child.offsetTopAndBottom(childTop - child.getTop());
 }

9. 提高性能的函数addViewInLayout
        if ((recycled && !p.forceAdd) || (p.recycledHeaderFooter &&
                p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER)) {
            attachViewToParent(child, flowDown ? -1 : 0, p);
        } else {
            p.forceAdd = false;
            if (p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {
                p.recycledHeaderFooter = true;
            }
            addViewInLayout(child, flowDown ? -1 : 0, p, true);
        }


0
0
分享到:
评论

相关推荐

    android面试题目

    在Android面试中,掌握核心知识点是至关重要的。以下是一些基于题目所提及的要点的详细解答,帮助你在面试中表现出色: 1. **点击图标启动A程序与B程序跳转到A程序的区别**: 当用户点击应用图标启动A程序时,这是...

    必看Android 500道高薪面试题集

    本文档是一本关于Android面试的题集,汇集了500道可能出现在Android开发工程师面试中的题目。涉及的知识点包括了Android基础知识、核心概念、系统架构、组件用法、数据存储、网络通信、设计模式、内存管理、缓存机制...

    android开发资料大全

    2011android面试题目及其答案大全.rar Android面试题集锦 (陆续更新)(最新2012-6-18) 【eoeAndroid Android相关的面试题最强汇总】 ZTE—adroid笔试题附答案版 iceskysl: 说说我招聘android技术人员的思路 史上...

    android面试题(阿里巴巴,腾讯,百度等公司)

    在Android开发领域,面试往往是对候选者技术能力的深度检验,尤其当面试来自阿里巴巴、腾讯、百度这样的顶级互联网公司时,面试题目会更加注重实际应用和技术深度。这些公司的面试题通常涵盖广泛,包括但不限于基础...

    [Android实例] 面试题集.zip

    【Android实例】面试题集.zip包含了丰富的Android开发相关的面试题目,是准备Android面试的重要参考资料。以下将对其中可能涵盖的知识点进行详细的解析。 1. **Android基础知识** - Android系统架构:了解Android...

    Android-TEST.rar_android

    这份名为"Android TEST.doc"的文档很可能是包含了一系列常见的Android面试题目,旨在帮助应聘者准备面试。以下是一些可能涵盖的关键知识点: 1. **Android基础知识**: - Android体系结构:包括Linux内核、库层、...

    博客园Android新教材各章面试题

    在Android开发领域,面试是检验...通过深入学习和掌握这些知识点,开发者可以更好地应对Android面试,提升自己的专业技能,同时也能在实际项目中游刃有余。不断跟进Android的新技术和最佳实践,是保持竞争力的关键。

    课程设计android 面试题 安卓巴士总结源代码下载

    这份"课程设计android 面试题 安卓巴士总结源代码下载"资源包含了丰富的Android面试知识点和实际的源代码示例,非常适合准备Android面试和提升编程技能的学习者。以下是根据标题、描述和标签提炼出的一些关键知识点...

    安卓部分面试题总结

    ### 安卓部分面试题知识点总结 #### 1. Intent 的几种有关 Activity 启动的...以上是针对安卓面试题中涉及到的一些核心知识点的总结,涵盖了 Android 开发中的多个方面,对于准备面试的同学来说是非常有用的参考资料。

    ViewAdapterTest源码

    9. **ListView与RecyclerView的区别**:虽然题目没有明确指出,但`ViewAdapterTest`可能涉及到`ListView`和`RecyclerView`。`RecyclerView`是`ListView`的升级版,提供了更强大的功能,如更好的性能、更灵活的布局...

Global site tag (gtag.js) - Google Analytics