【android】Adapter 的 convertView 复用浅析
2016-03-21 20:32
453 查看
目录
操作环境导读
参数说明
源码浅析
操作环境
操作系统: win7-64bit 旗舰版android 版本: android-23
导读
平时在使用 ListView 或 GridView 时,常需要自己复写 Adapter 的 View getView(int position, View convertView, ViewGroup parent) 方法,但对其中的 convertView 却不太了解,没法做到物尽其用;殊不知其用途可不小,可以在一定程度上避免 OOM参数说明
在 Adapter.java 中,对参数 convertView 的说明如下:说明: convertView 是一个可重用的 View,当然,也有可能是 Null;
良好的习惯是,在使用之前都检测一下;
/** * Get a View that displays the data at the specified position in the data set. You can either * create a View manually or inflate it from an XML layout file. When the View is inflated, the * parent View (GridView, ListView...) will apply default layout parameters unless you use * {@link android.view.LayoutInflater#inflate(int, android.view.ViewGroup, boolean)} * to specify a root view and to prevent attachment to the root. * * @param position The position of the item within the adapter's data set of the item whose view * we want. * @param convertView The old view to reuse, if possible. Note: You should check that this view * is non-null and of an appropriate type before using. If it is not possible to convert * this view to display the correct data, this method can create a new view. * Heterogeneous lists can specify their number of view types, so that this View is * always of the right type (see {@link #getViewTypeCount()} and * {@link #getItemViewType(int)}). * @param parent The parent that this view will eventually be attached to * @return */ View getView(int position, View convertView, ViewGroup parent);
源码浅析
再来看 AbsListView.java 的 obtainView 函数:说明:该函数的主要作用之一就是对 convertView 的复用;
AbsListView 维持:View[] mActiveViews 和 ArrayList mScrapViews 来对 convertView 进行回收管理的;
mScrapViews 主要用于存放不在 ListView 屏幕内那些 convertView,其内部的 convertView 的排列是没有一定顺序的,使用的时候需留意;
mActiveViews 则专门用于保存在 ListView 中显示的 convertView;
对于具有临时状态的 convertView,那么该 View 将不被纳入回收操作;
对于类型为 ITEM_VIEW_TYPE_HEADER_OR_FOOTER 的视图,也是不进行回收操作的;
对于其他的 convertView:首先通过 getScrapView( position ) 从 mScrapViews 中查询( 如果不存在,则需由之后的 getView 创建;如果存在,则将其返回,实现View的复用查询操作 );在调用 getView 函数后,如果得到一个新的 convertView,那么之前的 converView 将被继续保留在 mScrapViews 中,等待下一次根据 position 的查询;
/** * Get a view and have it show the data associated with the specified * position. This is called when we have already discovered that the view is * not available for reuse in the recycle bin. The only choices left are * converting an old view or making a new one. * * @param position The position to display * @param isScrap Array of at least 1 boolean, the first entry will become true if * the returned view was taken from the scrap heap, false if otherwise. * * @return A view displaying the data associated with the specified position */ View obtainView(int position, boolean[] isScrap) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "obtainView"); isScrap[0] = false; // Check whether we have a transient state view. Attempt to re-bind the // data and discard the view if we fail. final View transientView = mRecycler.getTransientStateView(position); if (transientView != null) { final LayoutParams params = (LayoutParams) transientView.getLayoutParams(); // If the view type hasn't changed, attempt to re-bind the data. if (params.viewType == mAdapter.getItemViewType(position)) { final View updatedView = mAdapter.getView(position, transientView, this); // If we failed to re-bind the data, scrap the obtained view. if (updatedView != transientView) { setItemViewLayoutParams(updatedView, position); mRecycler.addScrapView(updatedView, position); } } isScrap[0] = true; // Finish the temporary detach started in addScrapView(). transientView.dispatchFinishTemporaryDetach(); return transientView; } final View scrapView = mRecycler.getScrapView(position); final View child = mAdapter.getView(position, scrapView, this); if (scrapView != null) { if (child != scrapView) { // Failed to re-bind the data, return scrap to the heap. mRecycler.addScrapView(scrapView, position); } else { isScrap[0] = true; // Finish the temporary detach started in addScrapView(). child.dispatchFinishTemporaryDetach(); } } if (mCacheColorHint != 0) { child.setDrawingCacheBackgroundColor(mCacheColorHint); } if (child.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { child.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); } setItemViewLayoutParams(child, position); if (AccessibilityManager.getInstance(mContext).isEnabled()) { if (mAccessibilityDelegate == null) { mAccessibilityDelegate = new ListItemAccessibilityDelegate(); } if (child.getAccessibilityDelegate() == null) { child.setAccessibilityDelegate(mAccessibilityDelegate); } } Trace.traceEnd(Trace.TRACE_TAG_VIEW); return child; }
总结:
RecycleBin 提供了 mScrapViews 和 mActiveViews 来实现复用机制;
AbsListView 已经提供了 RecycleBin 机制,为我们尽可能的提供复用机制;但在平时开发使用的过程中,我们还是应当尽量避免无谓的 new 操作;
对于常用的 ListView 或者 GridView,如果 convertView 的布局大体都相同,可以尽量重用,避免 item 数量过大或过于分配频繁导致 OOM;
参考资料
http://www.android100.org/html/201507/26/168809.html
相关文章推荐
- 完美实现Android ListView中的TextView的跑马灯效果
- android上改变listView的选中颜色
- Delphi7中Listview的常用功能汇总
- Delphi控件ListView的属性及使用方法详解
- android中ListView数据刷新时的同步方法
- Android提高之ListView实现自适应表格的方法
- Android中实现水平滑动(横向滑动)ListView示例
- C#实现ListView选中项向上或向下移动的方法
- Listview加载的性能优化是如何实现的
- C#实现listview Group收缩扩展的方法
- C# listview添加combobox到单元格的实现代码
- ListView 百分比进度条(delphi版)
- Android listview多视图嵌套多视图
- php设计模式 Adapter(适配器模式)
- ListView Adapter优化 实例
- Android用ListView显示SDCard文件列表的小例子
- Adapter实现ListView带多选框等状态的自定义控件的注意事项
- 自定义Adapter并通过布局泵LayoutInflater抓取layout模板编辑每一个item实现思路
- ListView 使用问题
- 安卓listView的使用