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);
}
分享到:
相关推荐
在Android面试中,掌握核心知识点是至关重要的。以下是一些基于题目所提及的要点的详细解答,帮助你在面试中表现出色: 1. **点击图标启动A程序与B程序跳转到A程序的区别**: 当用户点击应用图标启动A程序时,这是...
本文档是一本关于Android面试的题集,汇集了500道可能出现在Android开发工程师面试中的题目。涉及的知识点包括了Android基础知识、核心概念、系统架构、组件用法、数据存储、网络通信、设计模式、内存管理、缓存机制...
2011android面试题目及其答案大全.rar Android面试题集锦 (陆续更新)(最新2012-6-18) 【eoeAndroid Android相关的面试题最强汇总】 ZTE—adroid笔试题附答案版 iceskysl: 说说我招聘android技术人员的思路 史上...
在Android开发领域,面试往往是对候选者技术能力的深度检验,尤其当面试来自阿里巴巴、腾讯、百度这样的顶级互联网公司时,面试题目会更加注重实际应用和技术深度。这些公司的面试题通常涵盖广泛,包括但不限于基础...
【Android实例】面试题集.zip包含了丰富的Android开发相关的面试题目,是准备Android面试的重要参考资料。以下将对其中可能涵盖的知识点进行详细的解析。 1. **Android基础知识** - Android系统架构:了解Android...
这份名为"Android TEST.doc"的文档很可能是包含了一系列常见的Android面试题目,旨在帮助应聘者准备面试。以下是一些可能涵盖的关键知识点: 1. **Android基础知识**: - Android体系结构:包括Linux内核、库层、...
在Android开发领域,面试是检验...通过深入学习和掌握这些知识点,开发者可以更好地应对Android面试,提升自己的专业技能,同时也能在实际项目中游刃有余。不断跟进Android的新技术和最佳实践,是保持竞争力的关键。
这份"课程设计android 面试题 安卓巴士总结源代码下载"资源包含了丰富的Android面试知识点和实际的源代码示例,非常适合准备Android面试和提升编程技能的学习者。以下是根据标题、描述和标签提炼出的一些关键知识点...
### 安卓部分面试题知识点总结 #### 1. Intent 的几种有关 Activity 启动的...以上是针对安卓面试题中涉及到的一些核心知识点的总结,涵盖了 Android 开发中的多个方面,对于准备面试的同学来说是非常有用的参考资料。
9. **ListView与RecyclerView的区别**:虽然题目没有明确指出,但`ViewAdapterTest`可能涉及到`ListView`和`RecyclerView`。`RecyclerView`是`ListView`的升级版,提供了更强大的功能,如更好的性能、更灵活的布局...