Android:BaseAdapter的优化方案一览
16lz
2021-01-26
1.什么是数据适配器?
用来建立数据源和数据渲染控件之间的关系,将数据的来源和数据的显示之间进行解耦,降低耦合性
2.BaseAdapter接口
BaseAdapter是一个抽象类(abstract)【以下代码为android源码】
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter { private final DataSetObservable mDataSetObservable = new DataSetObservable(); private CharSequence[] mAutofillOptions; public boolean hasStableIds() { return false; } public void registerDataSetObserver(DataSetObserver observer) { mDataSetObservable.registerObserver(observer); } public void unregisterDataSetObserver(DataSetObserver observer) { mDataSetObservable.unregisterObserver(observer); } /** * Notifies the attached observers that the underlying data has been changed * and any View reflecting the data set should refresh itself. */ public void notifyDataSetChanged() { mDataSetObservable.notifyChanged(); } /** * Notifies the attached observers that the underlying data is no longer valid * or available. Once invoked this adapter is no longer valid and should * not report further data set changes. */ public void notifyDataSetInvalidated() { mDataSetObservable.notifyInvalidated(); } public boolean areAllItemsEnabled() { return true; } public boolean isEnabled(int position) { return true; } public View getDropDownView(int position, View convertView, ViewGroup parent) { return getView(position, convertView, parent); } public int getItemViewType(int position) { return 0; } public int getViewTypeCount() { return 1; } public boolean isEmpty() { return getCount() == 0; } @Override public CharSequence[] getAutofillOptions() { return mAutofillOptions; } /** * Sets the value returned by {@link #getAutofillOptions()} */ public void setAutofillOptions(@Nullable CharSequence... options) { mAutofillOptions = options; }}
需要实现的抽象方法有四种
public int getCount() 适配器中数据集中数据的个数 listview显示的总数据public Object getItem(int position) 获取数据集中与指定索引对应的数据项public long getItemId(int position) 获取指定行对应的idpublic View getView(int position,View convertView,ViewGroup parent):获取每一个Item显示的内容
3.如何使用BaseAdapter和ListView进行联动?
3-1:准备含ListView的总布局文件
<?xml version="1.0" encoding="utf-8"?>
3-2:准备ListView中呈现的item的布局()
<?xml version="1.0" encoding="utf-8"?>
3-3:构建数据源:
package com.app.baseadaptertraining;//构建数据源public class ItemBean { public int itemImageResId; public String itemTitle; public String itemContent; //添加构造方法 public ItemBean(int itemImageResId, String itemTitle, String itemContent) { this.itemImageResId = itemImageResId; this.itemTitle = itemTitle; this.itemContent = itemContent; }}
3-4:实现数据适配器(可优化)
package com.app.baseadaptertraining;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.ImageView;import android.widget.TextView;import java.util.List;/** * BaseAdapter 抽象类 */public class MyAdapter extends BaseAdapter { private List mList; private LayoutInflater mInflater; //进行数据的初始化 //将数据源和数据适配器之间进行关联 public MyAdapter(Context context, List list) { mList = list; mInflater = LayoutInflater.from(context); } //返回ListView中的数据量 @Override public int getCount() { return mList.size(); } //取得所含有的数据项 @Override public Object getItem(int position) { return mList.get(position); } //返回数据项的索引 @Override public long getItemId(int position) { return position; } //返回每一项的内容 //没有缓存机制 @Override public View getView(int position, View convertView, ViewGroup parent) { //可以将xml文件装换称为view //开始装载视图 /** * 每一次都是创建新的view,没有实现缓存机制 实现资源的极大浪费 * 效率极其低下 * View view=mInflater.inflate(R.layout.item,null); * //找到视图中的三个控件 * ImageView imageView=(ImageView) view.findViewById(R.id.iv_image); * TextView title=(TextView)view.findViewById(R.id.tv_title); * TextView content=(TextView)view.findViewById(R.id.tv_content); * ItemBean bean=mList.get(position); * //开始进行数据的填充 * imageView.setImageResource(bean.itemImageResId); * title.setText(bean.itemTitle); * content.setText(bean.itemContent); * */ //******************************************************************* //第一种优化方案:避免重复去创建view对象 但是fingViewById依旧会浪费大量的时间// if (convertView == null) {// convertView = mInflater.inflate(R.layout.item, null);// }// ImageView imageView = (ImageView) convertView.findViewById(R.id.iv_image);// TextView title = (TextView) convertView.findViewById(R.id.tv_title);// TextView content = (TextView) convertView.findViewById(R.id.tv_content);// ItemBean bean = mList.get(position);// //开始进行数据的填充// imageView.setImageResource(bean.itemImageResId);// title.setText(bean.itemTitle);// content.setText(bean.itemContent);// return convertView; //********************************************************************* //第二种优化方案 //1.避免convertView以及findViewById的优化 //ViewHolder ViewHolder viewHolder; if (convertView == null) { viewHolder = new ViewHolder(); convertView = mInflater.inflate(R.layout.item, null); //载入数据 findViewById() viewHolder.imageView = (ImageView) convertView.findViewById(R.id.iv_image); viewHolder.content = (TextView) convertView.findViewById(R.id.tv_content); viewHolder.title = (TextView) convertView.findViewById(R.id.tv_title); //ViewHolder和convertView进行关联 convertView.setTag(viewHolder); } else { //取出关联的ViewHolder对象 viewHolder = (ViewHolder) convertView.getTag(); } ItemBean bean = mList.get(position); //开始进行数据的填充 viewHolder.imageView.setImageResource(bean.itemImageResId); viewHolder.title.setText(bean.itemTitle); viewHolder.content.setText(bean.itemContent); return convertView; } //避免重复进行findViewById() //建立映射条件 class ViewHolder { //对应布局中的三个控件 public ImageView imageView; public TextView title; public TextView content; }}
3-5:构建数据适配器和数据渲染器之间的联系(setAdapter)
package com.app.baseadaptertraining;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.widget.ListView;import java.util.ArrayList;import java.util.List;/** * 1.准备含ListView的总布局文件 * 2.准备单独的item文件 * 3.构造数据源(bean/pojo) * 4.实现数据适配器 BaseAdapter * 5.建立Adapter和ListView之间的联系 */public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); createMyList(); } private void createMyList() { List itemBeanList = new ArrayList<>(); //封装数据(准备假的数据) for (int i = 0; i < 20; i++) { //进行数据的填充 itemBeanList.add(new ItemBean(R.mipmap.ic_launcher, "这是一个title" + i, "这是一个content" + i)); } //建立Adapter和ListView的联系 ListView listView = (ListView) findViewById(R.id.lv_main); listView.setAdapter(new MyAdapter(this, itemBeanList)); }}
4.谈谈优化(主要是在构建Adapter的getView方法)
下面给出三种方案来构建视图
方案1:无优化,每一次均创建新的view,没有实现相应的缓存机制,实现资源的极大浪费
public View getView(int position, View convertView, ViewGroup parent) { //可以将xml文件装换称为view //开始装载视图 /** * 每一次都是创建新的view,没有实现缓存机制 实现资源的极大浪费 * 效率极其低下 * View view=mInflater.inflate(R.layout.item,null); * //找到视图中的三个控件 * ImageView imageView=(ImageView) view.findViewById(R.id.iv_image); * TextView title=(TextView)view.findViewById(R.id.tv_title); * TextView content=(TextView)view.findViewById(R.id.tv_content); * ItemBean bean=mList.get(position); * //开始进行数据的填充 * imageView.setImageResource(bean.itemImageResId); * title.setText(bean.itemTitle); * content.setText(bean.itemContent); return view; * */}
方案2:部分优化,借助自带的convertView进行优化
(判断convertView是否为空,从而杜绝每一次都要构建view的情况,但是重复findViewById()依旧会消耗极大的内存)
if (convertView == null) { convertView = mInflater.inflate(R.layout.item, null); } ImageView imageView = (ImageView) convertView.findViewById(R.id.iv_image); TextView title = (TextView) convertView.findViewById(R.id.tv_title); ItemBean bean = mList.get(position); //开始进行数据的填充 imageView.setImageResource(bean.itemImageResId); title.setText(bean.itemTitle); content.setText(bean.itemContent); return convertView;
方案3:全局优化,使用ViewHolder和convertView达到一种比较好的优化效果(相当于建立了两个缓存机制)
如果存在了视图组件,使用现成的convertView,无需重新创建
如果存在了控件,使用ViewHolder. 进行调用,无需重新查找控件位置
@Override public View getView(int position, View convertView, ViewGroup parent) { //1.避免convertView以及findViewById的优化 //ViewHolder ViewHolder viewHolder; if (convertView == null) { viewHolder = new ViewHolder(); convertView = mInflater.inflate(R.layout.item, null); //载入数据 findViewById() viewHolder.imageView = (ImageView) convertView.findViewById(R.id.iv_image); viewHolder.content = (TextView) convertView.findViewById(R.id.tv_content); viewHolder.title = (TextView) convertView.findViewById(R.id.tv_title); //ViewHolder和convertView进行关联 convertView.setTag(viewHolder); } else { //取出关联的ViewHolder对象 viewHolder = (ViewHolder) convertView.getTag(); } ItemBean bean = mList.get(position); //开始进行数据的填充 viewHolder.imageView.setImageResource(bean.itemImageResId); viewHolder.title.setText(bean.itemTitle); viewHolder.content.setText(bean.itemContent); return convertView; } //避免重复进行findViewById() //建立映射条件 class ViewHolder { //对应布局中的三个控件 public ImageView imageView; public TextView title; public TextView content; }
更多相关文章
- (Android学习之路)Android中listView结合自定义适配器,并实现item
- OpenDanmaku实现弹幕效果
- Android(安卓)Material Design控件之FloatingActionButton
- Android自定义UI实战(基础篇1)---组合控件封装
- Android-Module:ToggleButton常用XML属性
- Android(安卓)Parcel和Parcelable类
- Android实现Tab布局的4种方式(Fragment+TabPageIndicator+ViewPag
- RecyclerView 中 item 点击事件的优化
- 【Android】5.3 单选和复选