ListView的显示与缓存机制,需要才显示,显示完就被收回到缓存
BaseAdapter--数据适配器
public int getCount()---适配器中数据集中数据的个数
public Object getItem(int position)---获取数据集中与指定索引对应的数据项
public long getItemId(int position)---获取指定行对应的ID
public View getView(int position, View convertView, ViewGroup parent)---获取每一个Item的显示内容
public class MainActivity extends Activity{
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
List<ItemBean> itemBeanList = new ArrayList<>();
for(int i = 0; i<20; i++){
itemBeanList.add(new ItemBean(
R.mipmap.ic_launcher, "标题"+i, "内容"+i));
}
ListView listView = (ListView)findViewById(R.id.lv_main);
listView.setAdapter(new MyAdapter(this, itemBeanList));
}
}
public class MyAdapter extends BaseAdapter{
private List<ItemBean> mList;
private LayoutInflater mInflater;
public MyAdapter(Context context, List<ItemBean> list){
mList = list;
mInflater = LayoutInflater.from(context);
}
public int getCount(){
return mList.size();
}
public Object getItem(int position){
return mList.get(position);
}
public long getItemId(int position){
return position;
}
public View getView(int position, View convertView, ViewGroup parent){
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;
}
}
上述方法虽然正确,但是很浪费资源,没有利用ListView的缓存机制,没有任何的优化处理,效率极低。
以下是普通的方法,利用ListView的缓存机制,即使用系统提供的converView,而不是自己创建一个view,若没有缓存再创建一个新的View:
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;
因为避免了重复的创建converView对象,通过inflate对象将布局转化成一个View的时候很耗时耗资源,是很好的优化,但findViewById仍然会浪费大量时间
还有一种更优化的办法:
class ViewHolder{
public ImageView imageView;
public TextView title;
public TextView content;
}
ViewHolder viewHolder;
if(convertView == null){
//通过ViewHolder将需要通用findViewById查找的控件保存到ViewHolder中
//通过convertView.setTag将ViewHolder与convertView进行关联
//这样每个为空的converView通过inflate对象初始化布局之后,将所有的控件保存在ViewHolder对象中
//并通过setTag方法建立起converView与viewHolder的关联
//这样通过getTag方法找到converView中的一个viewholder的对象,即找到所声明的控件
//从而避免findViewById实例化,以提高效率
viewHolder = new ViewHolder();
convertView = mInflater.inflate(R.layout.item, null);
viewHolder.imageView = (ImageView)convertView.findViewById(R.id.iv_iamgeView);
viewHolder.title = (TextView)convertView.findViewById(R.id.tv_title);
viewHolder.content = (TextView)convertView.findViewById(R.id.tv_content);
convertView.setTag(viewHolder);
}else{
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方法查找控件,不仅利用了ListView的缓存,还通过ViewHolder类来实现显示数据的视图缓存
可以通过long start = System.nanoTime();和long end = System.nanoTime();来获取系统纳秒时间,long dValue = end - start; 来计算程序的操作用时,再通过Log.d("系统用时:"+String.valueOf(dValue));打印操作用时
通过ViewHolder优化BaseAdapter的思路:
创建Bean对象,用于封装数据
在构造方法中初始化用于映射的数据List
创建ViewHolder类,创建布局映射关系
判断convertView,为空则创建,并设置tag,否则通过tag来取出ViewHolder
给ViewHolder中的控件设置数据