ListView是一个非常常用的Android控件,通常情况下我们都需要去自定义ListView的Adapter以实现各种复杂的业务逻辑。但是需要注意的是,如果Adapter没有进行内存优化的话,ListView加载时会相当的占用内存,本文介绍了大部分情况下我们需要为自定义Adapter进行的内存优化工作。
下边的代码都是我在MarkDown里边敲的,没有做代码检查,如果要直接复制的话最好检查一下有没有错误。
内存优化的关键就是getView()方法,下边代码中省略了其他部分的逻辑。
应用情景:ListView中具有两种不同ListItem的布局,具有三种及以上也可参照此写法
- 布局1含有TextView,ImageView两个控件
- 布局2含有TextView,ImageView,Button三个控件
CustomAdapter.java
public class CustomAdapter extends BaseAdapter {
//省略构造方法
//省略其它复写方法
@override
public View getView(final int position, View convertView, ViewGroup parent) {
ListData itemData = getItem(position);
ViewHolder1 holder1 = null;
ViewHolder2 holder2 = null;
//switch根据不同数据加载不同的布局
switch(itemData.getDataType()){
case ListData.TYPE_ONE:
//下面这个R.id.item1这个id是我自己在values文件夹下的ids.xml添加的一个id,没有
//任何实际意义,只是为了标识这个存储的Tag而已。由于官方推荐使用具有唯一性id作为Tag
//的标识,所以需要自己去定义id,其中的原因有兴趣的可以去研究一下
if (converView == null || converView.getTag(R.id.item1)){
//若是之前还没有过ViewHolder存储则本次新建ViewHolder并存储
converView == LayoutInflater.from(context)
.inflate(R.layout.list_item1, parent, false);
holder1 = new ViewHolder1();
holder1.textView = (TextView)converView.findViewById(R.id.textview);
holder1.imageView = (ImageView)converView.findViewById(R.id.imageview);
converView.setTag(R.id.item1, holder1);
} else {
//之前有过存储则直接使用
holder1 = (ViewHolder1)converView.getTag(R.id.item1);
}
holder1.textView.setText(ListData.getStr());
holder1.imageView.setImageBitmap(BitmapFactory.decodeFile(ListData.getUrl));
break;
case ListData.TYPE_ONE:
if (converView == null || converView.getTag(R.id.item2)){
//若是之前还没有过ViewHolder存储则本次新建ViewHolder并存储
converView == LayoutInflater.from(context)
.inflate(R.layout.list_item2, parent, false);
holder2 = new ViewHolder2();
holder2.textView = (TextView)converView.findViewById(R.id.textview);
holder2.imageView = (ImageView)converView.findViewById(R.id.imageview);
holder2.button = (Button)converView.findViewById(R.id.button);
converView.setTag(R.id.item1, holder2);
} else {
holder2 = (ViewHolder1)converView.getTag(R.id.item1);
}
holder2.textView.setText(ListData.getStr());
holder2.imageView.setImageBitmap(BitmapFactory.decodeFile(ListData.getUrl));
holder2.button.setText(ListData.getButtonName());
break;
default:
break;
}
return convertView;
}
//布局1的ViewHolder
class ViewHolder1{
//定义布局包含的所有控件
TextView textView;
ImageView ImageView;
}
//布局2的ViewHolder
class ViewHolder2{
//定义布局内包含的所有控件
TextView textView;
ImageView ImageView;
Button button;
}
}
定义ListData数据格式方便Adapter使用数据
ListData.java
public class ListData{
//存储数据的相关变量
private int String str;
private String url;
private String buttonName;
private int dataType;
public static final int TYPE_ONE = 1;
public static final int TYPE_TWO = 2;
//数据格式1的构造函数
public ListData(String str, String url){
this.str = str;
this.url = url;
dataType = TYPE_ONE;
}
//数据格式2的构造函数
public ListData(String str, String url, String buttonName){
this.str = str;
this.url = url;
this.buttonName = buttonName;
dataType = TYPE_TWO;
}
//相关get方法
public String getStr(){
return str;
}
public String getUrl(){
return url;
}
public String getButtonName(){
return ButtonName;
}
public int getDataType(){
return dataType;
}
}
定义两个id用来标识ViewHolder
values/ids.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item type="id" name="item1">item1</item>
<item type="id" name="item2">item2</item>
</resources>
大致思想就是这样子的,通过ViewHolder将初始化过的控件保存起来,下次可以不用新创建就能直接使用存储的控件。这样的话一个ListView如果有2种ListItem的形式,那么最多创建两个ViewHolder就可以搞定,大大节省了内存支出。