4000-520-616
欢迎来到免疫在线!(蚂蚁淘生物旗下平台)  请登录 |  免费注册 |  询价篮
主营:原厂直采,平行进口,授权代理(蚂蚁淘为您服务)
咨询热线电话
4000-520-616
当前位置: 首页 > 新闻动态 >
热卖商品
新闻详情
实习入职第二十天:从setRecyclerListener看listView回..._CSDN博客
来自 : CSDN技术社区 发布时间:2021-03-25
3.1 ListView 3.1.1 layoutChildren

1479-1729

     1583-当数据发生改变的时候 把当前的view放到scrapviews里面 否则标记为activeViews。

// Pull all children into the RecycleBin.

// These views will be reused if possible

final int firstPosition mFirstPosition;

final RecycleBin recycleBin mRecycler;

if (dataChanged) {

for (int i i childCount; i ) {

recycleBin.addScrapView(getChildAt(i), firstPosition

}

}else {

recycleBin.fillActiveViews(childCount, firstPosition);

}

// Clear out old views

detachAllViewsFromParent();

recycleBin.removeSkippedScrap();//移除所有old views

......

// Flush any cached views that did not get reused above

recycleBin.scrapActiveViews();//刷新缓存 将当前的ActiveVies 移动到 ScrapViews。

dataChanged 从单词的意思我们就可以 这里的优化规则就是基于数据是否有变化 mDataChanged在makeAndAddView 见下文 中有使用。

     step1 如果数据发生变化 就将所有view加入到mScrapView中 否则 将所有view放到mActiveView中

   step2 添加view到listview中

           step3 回收mActiveView中的未使用的view到mScrapView中

       注 在step1中 如果是addScrapView 则所有的view将会detach 如果是fillActiveViews 则不会detach 只有在step3中 未用到的view才会detach。

 

3.1.2 makeAndAddView

(int position, int y, boolean flow, int childrenLeft, boolean selected)(1772)

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.

View child;

if (!mDataChanged) {// 数据没有更新时 使用以前的view

// Try to use an existing view for this position

child mRecycler.getActiveView(position);

if (child !  null) {

// Found it -- we re using an existing child

// This just needs to be positioned

// 对复用的View针对当前需要进行配置。定位并且添加这个view到ViewGrop中的children列表 从回收站获取的视图不需要measure 所以最后一个参数为true

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;

 

3.1.3 setupChild

(View child, int position, int y, boolean flowDown, int childrenLeft, boolean selected, boolean recycled) 1812

Add a view as a child and make sure it is measured (if necessary) and positioned properly.

 

3.1.4 setAdapter

(ListAdapter adapter) (457)

Sets the data behind this ListView. The adapter passed to this method may be wrapped by a WrapperListAdapter, depending on the ListView features currently in use. For instance, adding headers and/or footers will cause the adapter to be wrapped.

if (mAdapter !  null  mDataSetObserver !  null) {

mAdapter.unregisterDataSetObserver(mDataSetObserver);//移除了与当前listview的adapter绑定数据集观察者DataSetObserver

}

resetList();//重置listview 主要是清除所有的view 改变header、footer的状态

mRecycler.clear();//清除掉RecycleBin对象mRecycler中所有缓存的view RecycleBin后面着重介绍 主要是关系到Listview中item的重用机制 它是AbsListview的一个内部类

if (mHeaderViewInfos.size() 0|| mFooterViewInfos.size() 0) { //判断是否有headerview和footview

mAdapter  new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);

} else {

mAdapter adapter;

}

mOldSelectedPosition  INVALID_POSITION;

mOldSelectedRowId  INVALID_ROW_ID;

// AbsListView#setAdapter will update choice mode states.

super.setAdapter(adapter);

 

if (mAdapter !  null) {

mAreAllItemsSelectable  mAdapter.areAllItemsEnabled();

mOldItemCount mItemCount;

mItemCount mAdapter.getCount();

checkFocus();

mDataSetObserver  new AdapterDataSetObserver();//注册headerview的观察者

mAdapter.registerDataSetObserver(mDataSetObserver);//在RecycleBin对象mRecycler记录下item类型的数量

mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());

int position;

if (mStackFromBottom) {

position lookForSelectablePosition(mItemCount - 1, false);

} else {

position lookForSelectablePosition(0, true);

}

setSelectedPositionInt(position);//AdapterView中的方法 记录当前的position

setNextSelectedPositionInt(position);//AdapterView中的方法 记录下一个position

if (mItemCount 0) {

// Nothing selected

checkSelectionChanged();

}

} else {

mAreAllItemsSelectable   true;

checkFocus();

// Nothing selected

checkSelectionChanged();

}

requestLayout();

 

 

3.1.5 scrollListItemsBy

(int amount) 3012-3082

对子view滑动一定距离 添加view到底部或者移除顶部的不可见view。从注释看 不可见的item 的自动移除是在scrollListItemsBy中进行的。

 

private void scrollListItemsBy(int amount) {

offsetChildrenTopAndBottom(amount);

final int listBottom getHeight() - mListPadding.bottom;//获取listview最底部位置

final int listTop mListPadding.top; //获取listview最顶部位置

final AbsListView.RecycleBin recycleBin mRecycler;

if (amount 0) {

// shifted items up

// may need to pan views into the bottom space

int numChildren getChildCount();

View last getChildAt(numChildren - 1);

while (last.getBottom() listBottom) {//最后的view高于底部时添加下一个view

final int lastVisiblePosition  mFirstPosition numChildren - 1;

if (lastVisiblePosition mItemCount - 1) {

last addViewBelow(last, lastVisiblePosition);

numChildren

} else {

break;

}

}

// may have brought in the last child of the list that is skinnier

// than the fading edge, thereby leaving space at the end. need

// to shift back

if (last.getBottom() listBottom) {//到达最后一个view

offsetChildrenTopAndBottom(listBottom - last.getBottom());

}

// top views may be panned off screen

View first getChildAt(0);

while (first.getBottom() listTop) {//顶部view移除屏幕时

AbsListView.LayoutParams layoutParams (LayoutParams) first.getLayoutParams();

if (recycleBin.shouldRecycleViewType(layoutParams.viewType)) {

recycleBin.addScrapView(first, mFirstPosition); //回收view

}

detachViewFromParent(first); //从父类中移除

first getChildAt(0); //这行好像没用啊。。。。

mFirstPosition

}

} else {

// shifted items down

View first getChildAt(0);

// may need to pan views into top

while ((first.getTop() listTop) (mFirstPosition 0)) {//顶部view上部有空间时添加view。

first addViewAbove(first, mFirstPosition);

mFirstPosition--;

}

// may have brought the very first child of the list in too far and

// need to shift it back

if (first.getTop() listTop) {//到达第一个view

offsetChildrenTopAndBottom(listTop - first.getTop());

}

int lastIndex getChildCount() - 1;

View last getChildAt(lastIndex);

// bottom view may be panned off screen

while (last.getTop() listBottom) {//底部view移除屏幕的情况

AbsListView.LayoutParams layoutParams (LayoutParams) last.getLayoutParams();

if (recycleBin.shouldRecycleViewType(layoutParams.viewType)) {

recycleBin.addScrapView(last, mFirstPosition lastIndex);

}

detachViewFromParent(last);

last getChildAt(--lastIndex);

}

}

}

 

从以上代码可以看出 Android中view回收的计算是其父view中不再显示的 如果scrollview中包含了一个wrap_content属性的listview 里面的内容并不会有任何回收 引起listview 的getheight函数获取的是一个足以显示所有内容的高度。

3.2 AbsListView      3.2.1 obtainView

(int position, boolean[] isScrap)(2227)

    Get a view and have it show the data associated with the specified position. 当这个方法被调用时 说明Recycle bin中的view已经不可用了 那么 现在唯一的方法就是 convert一个老的view 或者构造一个新的view。

position: 要显示的位置

isScrap: 是个boolean数组, 如果view从scrap heap获取 isScrap [0]为true,否则为false。

 

isScrap[0]  false;

View scrapView;

scrapView  mRecycler.getTransientStateView(position);

if (scrapView  null) {

// 查看回收站中是否有废弃无用的View 如果有 则使用它 无需New View。

scrapView  mRecycler.getScrapView(position);

}

View child;

if (scrapView !  null) { //此时说明可以从回收站中重新使用scrapView。

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

if(child.getImportantForAccessibility()  IMPORTANT_FOR_ACCESSIBILITY_AUTO) {

child.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);

}

if (child ! scrapView) {

//如果重用的scrapView和adapter获得的view是不一样的 将scrapView进行回收  

mRecycler.addScrapView(scrapView, position);// scrapView 仍然放入回收站

if (mCacheColorHint ! 0) {

child.setDrawingCacheBackgroundColor(mCacheColorHint);

}

} else {

//如果重用的view和adapter获得的view是一样的 将isScrap[0]值为true 否则默认为false

isScrap[0]  true;

// Clear any system-managed transient state so that we can

// recycle this view and bind it to different data.

if (child.isAccessibilityFocused()) {

child.clearAccessibilityFocus();

}

child.dispatchFinishTemporaryDetach();

}

}else {//回收站中没有拿到数据 就只能够自己去inflate一个xml布局文件 或者new一个view

child  mAdapter.getView(position, null, this); //当getview中传入的

converView null的时候会在getView的方法中进行新建这个view  

if (child.getImportantForAccessibility()  IMPORTANT_FOR_ACCESSIBILITY_AUTO) {

child.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);

}

if (mCacheColorHint ! 0) {

child.setDrawingCacheBackgroundColor(mCacheColorHint);

}

}

 

     3.2.2 trackMotionScroll

(int deltaY, int incrementalDeltaY)(4991)

监视滑动动作

deltaY: Amount to offset mMotionView. This is the accumulated delta since the motion began. 正数表示向下滑动。

incrementalDeltaY :Change in deltaY from the previous event.

.......

// 滚动时 不在可见范围内的item放入回收站。。。。。。。

if (down) {

int top -incrementalDeltaY;

if ((mGroupFlags  CLIP_TO_PADDING_MASK)  CLIP_TO_PADDING_MASK) {

top listPadding.top;

}

for (int i i childCount; i ) {

final View child getChildAt(i);

if (child.getBottom() top) {

break;

} else {

count

int position firstPosition

if (position headerViewsCount position footerViewsStart) {

// The view will be rebound to new data, clear any

// system-managed transient state.

if (child.isAccessibilityFocused()) {

child.clearAccessibilityFocus();

}

mRecycler.addScrapView(child, position);//放入回收站

}

}

}

} else {

int bottom getHeight() - incrementalDeltaY;

if ((mGroupFlags  CLIP_TO_PADDING_MASK)  CLIP_TO_PADDING_MASK) {

bottom - listPadding.bottom;

}

for (int i childCount - 1; i i--) {

final View child getChildAt(i);

if (child.getTop() bottom) {

break;

} else {

start

count

int position firstPosition

if (position headerViewsCount position footerViewsStart) {

// The view will be rebound to new data, clear any

// system-managed transient state.

if (child.isAccessibilityFocused()) {

child.clearAccessibilityFocus();

}

mRecycler.addScrapView(child, position);//放入回收站

}

}

}

}

 

 

4. 用到的关键类 4.1 ViewType的使用

在listview中当有多种viewtype的时候 在adapter中继承设置getItemViewType方法可以更有效率 。示例如下

.......

private static final int TYPE_ITEM

private static final int TYPE_SEPARATOR

private static final int TYPE_MAX_COUNT TYPE_SEPARATOR

 

Override

public int getItemViewType(int position) {

return mSeparatorsSet.contains(position) ? TYPE_SEPARATOR : TYPE_ITEM;

}

Override

public int getViewTypeCount() {

return TYPE_MAX_COUNT;

}

 

Override

public View getView(int position, View convertView, ViewGroup parent) {

ViewHolder holder null;

int type  getItemViewType(position);

if (convertView null) {

holder new ViewHolder();

switch (type) {

case TYPE_ITEM:

convertView mInflater.inflate(R.layout.item1, null);

holder.textView (TextView)convertView.findViewById......;

break;

case TYPE_SEPARATOR:

convertView mInflater.inflate(R.layout.item2, null);

holder.textView (TextView)convertView.findViewById......;

break;

}

convertView.setTag(holder);

} else {

holder (ViewHolder)convertView.getTag();

}

........

 

 

 

 

 

 

 

如果实现了RecyclerListener接口 当一个View由于ListView的滑动被系统回收到RecycleBin的mScrapViews数组时 会调用RecyclerListener中的onMovedToScrapHeap(View view)方法。RecycleBin相当于一个临时存储不需要显示的那部分Views的对象 随着列表滑动 这些Views需要显示出来的时候 他们就被从RecycleBin中拿了出来 RecycleBin本身并不对mScrapViews中的对象做回收操作。

于是在工程里 为ListView添加RecyclerListener接口 并在onMovedToScrapHeap方法中释放ListItem包含的Bitmap资源 这样可以极大的减少内存占用。

 

 

4.2 TransientStateView

用来标记这个view的瞬时状态 用来告诉app无需关心其保存和恢复。从注释看 这种具有瞬时状态的view 用于在view动画播放等情况中。

本文链接: http://scraponline.immuno-online.com/view-757000.html

发布于 : 2021-03-25 阅读(0)
公司介绍
品牌分类
联络我们
服务热线:4000-520-616
(限工作日9:00-18:00)
QQ :1570468124
手机:18915418616
官网:http://