ListView的优化主要包括5点:
1.对convertView进行非空复用
2.利用ViewHolder将findViewById获取到的资源保存起来,以便复用
3.滚屏时不加载耗费资源的信息
4.耗时操作(如网络获取图片)异步处理
5.将耗时获取的信息缓存以备复用
更多细节,请查看如下源码。
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class CAdapter extends BaseAdapter {
private static final String LOG_TAG = "CAdapter";
private Context mContext;
private List<Map<String, Object>> mList;
private LayoutInflater mInflater;
private ImageCache mImageCache;
private int lastSrollState;
private boolean isBusy = false;
public CAdapter(Context context, AbsListView listView, List<Map<String, Object>> list) {
super();
mList = list;
mContext = context;
mInflater = LayoutInflater.from(context);
mImageCache = new ImageCache();
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// Log.e(LOG_TAG, "scrollState=" + scrollState);
switch (scrollState) {
case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:
turnOnLoad();
if (lastSrollState == AbsListView.OnScrollListener.SCROLL_STATE_FLING) {
bindData(view);
}
break;
case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
turnOnLoad();
break;
case AbsListView.OnScrollListener.SCROLL_STATE_FLING:
turnOffLoad();
break;
}
lastSrollState = scrollState;
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
}
});
}
public void turnOnLoad() {
isBusy = false;
}
public void turnOffLoad() {
isBusy = true;
}
@Override
public int getCount() {
if (mList == null) {
return 0;
} else {
return mList.size();
}
}
@Override
public Map<String, Object> getItem(int position) {
if (mList == null) {
return null;
} else {
return mList.get(position);
}
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
//优化1.对convertView进行非空复用
if (convertView == null) {
Log.e(LOG_TAG,
"create view from inflater." + position + " cache size " + mImageCache.size());
holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.listview_item, parent, false);
holder.photo = (ImageView) convertView.findViewById(R.id.imageView);
holder.name = (TextView) convertView.findViewById(R.id.name);
holder.time = (TextView) convertView.findViewById(R.id.time);
//优化2.利用ViewHolder将findViewById获取到的资源保存起来,以便复用
convertView.setTag(holder);
} else {
// Log.e(LOG_TAG, "create view from holder." + position);
holder = (ViewHolder) convertView.getTag();
}
bindData(position, holder);
return convertView;
}
public void bindData(AbsListView listView) {
int firstVisibleItem = listView.getFirstVisiblePosition();
int visibleItemCount = listView.getChildCount();
Log.e(LOG_TAG, "bind data from item:" + firstVisibleItem + " to item:"
+ (firstVisibleItem + visibleItemCount - 1));
// listview.getChildAt(firstVisibleItem);
for (int i = 0; i < visibleItemCount; i++) {
bindData(firstVisibleItem + i, (ViewHolder) listView.getChildAt(i).getTag());
}
}
private void bindData(int position, ViewHolder holder) {
Log.e(LOG_TAG, "bind data for item:" + position);
Map<String, Object> item = mList.get(position);
holder.name.setText((String) item.get(MainActivity.KEY_NAME));
holder.time.setText((String) item.get(MainActivity.KEY_TIME));
//优化3.滚屏时不加载耗费资源的信息
//耗时的图片加载,在滚屏过程中不加载
if (!isBusy) {
ImageModel imageModel = mImageCache.getImageModel(position);
//缓存中没有,异步加载
if (imageModel == null) {
mImageCache.putEmptyImage(position);
//优化4.耗时操作(如网络获取图片)异步处理
new ImageLoader().execute(holder.photo, (Integer) item.get(MainActivity.KEY_PHOTO),
position);
//缓存中有,直接从缓存加载
} else {
if (imageModel.image == null) {
Log.e(LOG_TAG, "async loading image" + position);
} else {
Log.e(LOG_TAG, "load image" + position + " from cache");
holder.photo.setImageBitmap(imageModel.image);
}
}
}
}
class ImageLoader extends AsyncTask<Object, Integer, Bitmap> {
private ImageView imageView;
private int position;
public ImageLoader() {
}
// params[0]->imageView; params[1]->resourcesId; params[2]->position;
@Override
protected Bitmap doInBackground(Object... params) {
imageView = (ImageView) params[0];
int resourcesId = (Integer) params[1];
position = (Integer) params[2];
Log.e(LOG_TAG, "async load image" + position + " start...");
return BitmapFactory.decodeResource(mContext.getResources(), resourcesId);
}
@Override
protected void onPostExecute(Bitmap image) {
imageView.setImageBitmap(image);
//优化5.将耗时获取的信息缓存以备复用
//将异步获取到的图片保存到缓存中,避免每次都去目标位置获取,尤其对网络请求图片请求很有意义
mImageCache.getImageModel(position).image = image;
Log.e(LOG_TAG, "async load image" + position + " end, and update cache.");
}
}
static class ViewHolder {
private TextView name;
private TextView time;
private ImageView photo;
}
static class ImageCache {
LinkedList<ImageModel> cache = new LinkedList<ImageModel>();
void putEmptyImage(int position) {
cache.push(new ImageModel(position));
}
void updateImage(int position, Bitmap image) {
ImageModel model = getImageModel(position);
model.image = image;
}
ImageModel getImageModel(int position) {
for (ImageModel model : cache) {
if (model.position == position) {
return model;
}
}
return null;
}
int size() {
return cache.size();
}
}
static class ImageModel {
int position;
Bitmap image;
ImageModel(int position) {
this.position = position;
}
}
}