优化ListView加载数据逻辑
一、ListView介绍
在android开发中Listview是一个很重要的组件,它以列表的形式根据数据的长自适应展示具体内容,用户可以自由的定义listview每一列的布局,但当listview有大量的数据需要加载的时候,会占据大量内存,影响性能,这时候就需要按需填充并重新使用view来减少对象的创建。
它以列表的形式展示数据内容,并且能够根据列表的高度自适应屏幕显示
二、表现形式
这就是一种最简单的 ListView 的表现形式,黑色框就是 ListView 控件,其中由一个个的 item 组成(红色框内容),然后可以通过向下滑动来查看很多的条目。
三、工作原理
ListView 仅是作为容器(列表),用于装载显示数据(就是上面的一个个的红色框的内容,也称为 item)。item 中的具体数据是由适配器(adapter)来提供的。
当需要显示数据的时候,ListView 会从适配器(Adapter)中取出数据,然后来加载数据。
四、常用的数据适配器(Adapter)
1.BaseAdapter
BaseAdapter是基本的适配器。其实实际上就是一个抽象类,通常在自定义适配器时会继承BaseAdapter,该类拥有四个抽象方法,根据这几个抽象方法来对ListView控件进行数据适配。
BaseAdapter的四个抽象方法:
方法名称 | 功能 描述 |
---|---|
public int getCount() | 获取Item条目的总数 |
pyblic Object getItem(int position) | 根据position(位置)获取某个Item的对象 |
public long getItemId(int position) | 根据position(位置)获取某个Item的id |
public View getView(int position,View convertView,ViewGroup parent) | 获取相应position对应的Item视图,position是当前Item的位置,converView用于复用旧视图,parent用于加载XML布局 |
2.SimpleAdapter
SimpleAdapter继承自BaseAdapter,实现了BaseAdapter的四个抽象方法并对其进行封装。因此在使用SimpleAdapter进行数据适配时,只需要在构造方法中传入相应的参数即可,SimpleAdapter的构造方法的具体信息如下:
public SimpleAdapter(Context context,List<? extends Map<String,?>> data,int resourse,String[] from,int[] to)
在SimpleAdapter()构造方法中的5个参数的含义:
- context:表示上下文对象
- data:数据集合,data中的每一项对应ListView控件中的条目的数据
- resourse:Item布局的资源id
- from:Map集合中的key值
- to:Item布局中对应的控件
3.ArrayAdapter
ArrayAdapter也是BaseAdapter的子类,用法与SimpleAdapter类似,开发者只需要在构造方法里面传入相应参数即可。ArrayAdapter通常用于适配TextView控件,例如Android系统中的Setting(设置菜单)。ArrayAdapter有多个构造方法,ArrayAdapter构造方法具体信息如下:
public ArrayAdapter(Context context,int resourse);
public ArrayAdapter(Context context,int resourse,int textViewResourceId);
public ArrayAdapter(Context context,int resourse,T[] objects);
public ArrayAdapter(Context context,int resourse,int textViewResourceId,T[] objects);
public ArrayAdapter(Context context,int resourse,List<T> objects);
public ArrayAdapter(Context context,int resourse,int textViewResourceId,List<T> objects);
在ArrayAdapter()构造方法中的5个参数的含义:
- context:表示上下文对象
- resourse:Item布局的资源id
- textViewResourceId:Item布局中相应TextView的id
- T[] objects:需要适配的数组类型的数据
- List objects:需要适配的List类型的数据
五、优化方式
优化listview的加载速度就要让convertView匹配列表类型,并最大程度上的重新使用convertView。
getview的加载方法一般有以下三种种方式:
1.每一次都重新定义一个View载入布局,再加载数据(最慢的加载方式)
public View getView(int position, View convertView, ViewGroup parent) {
View item = mInflater.inflate(R.layout.list_item_icon_text, null);
((TextView) item.findViewById(R.id.text)).setText(DATA[position]);
((ImageView) item.findViewById(R.id.icon)).setImageBitmap(
(position & 1) == 1 ? mIcon1 : mIcon2);
return item;
}
2.convertView不为空的时候直接重新使用
从而减少了很多不必要的View的创建,然后加载数据
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item, parent, false);
}
((TextView) convertView.findViewById(R.id.text)).setText(DATA[position]);
((ImageView) convertView.findViewById(R.id.icon)).setImageBitmap(
(position & 1) == 1 ? mIcon1 : mIcon2);
return convertView;
}
3.定义一个ViewHolder
将convetView的tag设置为ViewHolder,不为空时重新使用即可(最快的方式)
static class ViewHolder {
TextView text;
ImageView icon;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item_icon_text,
parent, false);
holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(R.id.text);
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.text.setText(DATA[position]);
holder.icon.setImageBitmap((position & 1) == 1 ? mIcon1 : mIcon2);
return convertView;
}