Listview异步加载图片网上有很多这方面的资料,对网上的一些解决方案做了整合,最终写了一个"线程池"+"LruCache缓存"+"tag防止错位"的demo,主要代码如下:
MainActivity.java
package com.syncloadbmp;
import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.widget.ListView;
public class MainActivity extends Activity {
private ArrayList<PicItem> mPicList;
private PicAdapter mPicAdapter;
private ListView mListView;
private Context mContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mContext = MainActivity.this;
mListView = (ListView) findViewById(R.id.listview);
mPicList = new ArrayList<PicItem>();
String[] imageArray = new String[] {
"http://www.uuuu.cc/uploads/allimg/c120608/13391223A103P-DQ30.jpg",
"http://c.hiphotos.baidu.com/image/pic/item/e1fe9925bc315c60163c29ee8fb1cb1349547701.jpg",
"http://b.hiphotos.baidu.com/image/pic/item/1ad5ad6eddc451dac09faffbb7fd5266d01632b0.jpg",
"http://d.hiphotos.baidu.com/image/pic/item/4afbfbedab64034f0b30770fadc379310a551d3d.jpg",
"http://f.hiphotos.baidu.com/image/pic/item/9f2f070828381f306c7d2ba7ab014c086e06f05c.jpg",
"http://g.hiphotos.baidu.com/image/pic/item/d0c8a786c9177f3e29b9a50072cf3bc79f3d5629.jpg",
"http://h.hiphotos.baidu.com/image/pic/item/d4628535e5dde7116fdcfeffa5efce1b9d1661a9.jpg",
"http://e.hiphotos.baidu.com/image/pic/item/2934349b033b5bb51d2a95f734d3d539b600bc3e.jpg",
"http://g.hiphotos.baidu.com/image/pic/item/f636afc379310a551566b9fcb54543a982261073.jpg",
"http://e.hiphotos.baidu.com/image/pic/item/241f95cad1c8a786b58c43036509c93d70cf501c.jpg",
"http://d.hiphotos.baidu.com/image/pic/item/908fa0ec08fa513dbdbdcdd03f6d55fbb2fbd9ad.jpg",
"http://e.hiphotos.baidu.com/image/pic/item/e850352ac65c1038b72980c5b0119313b07e8966.jpg",
"http://d.hiphotos.baidu.com/image/pic/item/7acb0a46f21fbe096810b61c69600c338744ad6f.jpg",
"http://f.hiphotos.baidu.com/image/pic/item/6159252dd42a2834d1c76f0259b5c9ea15cebf52.jpg",
"http://f.hiphotos.baidu.com/image/pic/item/4bed2e738bd4b31c0a3722bc85d6277f9e2ff8aa.jpg",
"http://e.hiphotos.baidu.com/image/pic/item/e61190ef76c6a7ef3a500b28fffaaf51f3de664e.jpg",
"http://b.hiphotos.baidu.com/image/pic/item/e1fe9925bc315c601dc62ee88fb1cb1349547761.jpg",
"http://h.hiphotos.baidu.com/image/pic/item/6a63f6246b600c3340c26bcf184c510fd9f9a17a.jpg",
"http://a.hiphotos.baidu.com/image/pic/item/7c1ed21b0ef41bd5f500a6f353da81cb39db3d61.jpg",
"http://c.hiphotos.baidu.com/image/pic/item/29381f30e924b899336ecd9f6f061d950b7bf6c3.jpg",
"http://a.hiphotos.baidu.com/image/pic/item/18d8bc3eb13533faa27e2b29aad3fd1f40345be8.jpg",
"http://c.hiphotos.baidu.com/image/pic/item/3b87e950352ac65ce2e93f6ef9f2b21193138a3b.jpg",
"http://d.hiphotos.baidu.com/image/pic/item/6c224f4a20a44623b247ee659a22720e0cf3d72c.jpg",
"http://d.hiphotos.baidu.com/image/pic/item/023b5bb5c9ea15cedd54be0eb4003af33a87b27b.jpg",
"http://e.hiphotos.baidu.com/image/pic/item/3b87e950352ac65cfc372174f9f2b21193138a83.jpg",
"http://c.hiphotos.baidu.com/image/pic/item/b151f8198618367a583cc3aa2c738bd4b31ce514.jpg",
"http://b.hiphotos.baidu.com/image/pic/item/8694a4c27d1ed21b5f1c9bf8af6eddc450da3fd1.jpg",
"http://d.hiphotos.baidu.com/image/pic/item/3bf33a87e950352ab532fa045143fbf2b2118b6f.jpg",
"http://b.hiphotos.baidu.com/image/pic/item/d0c8a786c9177f3e5682407a72cf3bc79f3d5616.jpg" };
for (int i = 0; i < imageArray.length; i++) {
PicItem item = new PicItem();
item.mImageUrl = imageArray[i];
mPicList.add(item);
}
mPicAdapter = new PicAdapter(mContext, mPicList);
mListView.setAdapter(mPicAdapter);
}
}
PicAdapter.java
package com.syncloadbmp;
import java.util.ArrayList;
import com.syncloadbmp.BitmapLoader.DisplayImageListener;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
public class PicAdapter extends BaseAdapter {
private ArrayList<PicItem> mPicList;
private Context mContext;
public PicAdapter(Context context, ArrayList<PicItem> list) {
mContext = context;
mPicList = list;
}
@Override
public int getCount() {
return mPicList.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Holder holder = null;
if (convertView == null) {
Log.v("YAN-G", "new view");
convertView = View.inflate(mContext, R.layout.pic_item, null);
holder = new Holder();
holder.mImageView = (ImageView) convertView
.findViewById(R.id.image);
convertView.setTag(holder);
}
// 使用holder能够避免每次都做findViewById的操作
holder = (Holder) convertView.getTag();
final PicItem item = mPicList.get(position);
holder.mImageView.setTag(item.mImageUrl);
// -- start 不加这段代码图片加载时会错位,后面会刷新恢复,但有延迟
Bitmap bmp = BitmapLoader.getInstance().getBitmapFromMemCache(
item.mImageUrl);
if (bmp != null) {
holder.mImageView.setBackgroundDrawable(new BitmapDrawable(bmp));
} else {
holder.mImageView.setBackgroundResource(R.drawable.ic_launcher);
}
// -- end
BitmapLoader.getInstance().loadBitmap(item.mImageUrl,
holder.mImageView, new DisplayImageListener() {
@Override
public void showImage(ImageView image, Bitmap bmp) {
// 不加上这句,上下滚动过快或者网络比较慢的时候就会出现图片错位的问题
// 因为listview会换成view,无论向上还是向下列表里引用的还是同一个view,
// 图片加载又是异步的因此会有错位的情况,但如果每次都更新view的tag,这样就能保证
// 引用的view所标记的tag是最新的,就不会错位
if (item.mImageUrl.equals(image.getTag())) {
image.setBackgroundDrawable(new BitmapDrawable(bmp));
}
}
});
return convertView;
}
class Holder {
public ImageView mImageView;
}
}
BitmapLoader.java
package com.syncloadbmp;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.util.LruCache;
import android.widget.ImageView;
public class BitmapLoader {
private static BitmapLoader mBitmapLoader;
private ExecutorService mThreadService;
private LruCache<String, Bitmap> mBmpCache;
public static BitmapLoader getInstance() {
if (mBitmapLoader == null) {
mBitmapLoader = new BitmapLoader();
}
return mBitmapLoader;
}
public BitmapLoader() {
mThreadService = Executors.newFixedThreadPool(6);
int maxMemory = (int) Runtime.getRuntime().maxMemory();
int cacheSize = maxMemory / 4;
// 给LruCache分配1/8 4M
mBmpCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
// TODO Auto-generated method stub
return value.getRowBytes() * value.getHeight();
}
};
}
public void addBitmapToCache(String key, Bitmap bmp) {
if (getBitmapFromMemCache(key) == null && bmp != null) {
mBmpCache.put(key, bmp);
}
}
public Bitmap getBitmapFromMemCache(String key) {
return mBmpCache.get(key);
}
public void loadBitmap(final String url, final ImageView image,
final DisplayImageListener listener) {
final Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
listener.showImage(image, (Bitmap) msg.obj);
}
};
Bitmap bmp = getBitmapFromMemCache(url);
if (bmp != null) {
Log.v("YAN-G", "not null");
listener.showImage(image, bmp);
return;
}
mThreadService.execute(new Runnable() {
@Override
public void run() {
Log.v("YAN-G", "load bmp from net");
Bitmap bitmap = getBitmapFormUrl(url, true, 100, 80);
Message msg = Message.obtain();
msg.obj = bitmap;
handler.sendMessage(msg);
addBitmapToCache(url, bitmap);
}
});
}
public void destroy() {
mThreadService.shutdown();
}
public Bitmap getBitmapFormUrl(String url, boolean isCompress, float f,
float g) {
URL myFileUrl = null;
Bitmap bitmap = null;
if (null == url || url.equals("") || url.endsWith(".com")) {
return null;
}
try {
myFileUrl = new URL(url);
} catch (MalformedURLException e) {
e.printStackTrace();
}
try {
HttpURLConnection conn = (HttpURLConnection) myFileUrl
.openConnection();
conn.setDoInput(true);
conn.connect();
InputStream is = conn.getInputStream();
if (null != is && is.available() >= 0) {
if (isCompress) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
// 获取这个图片的宽和高
bitmap = BitmapFactory.decodeStream(is, null, options);
options.outWidth = (int) f;
options.outHeight = (int) g;
options.inSampleSize = (int) (options.outWidth / f);
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inJustDecodeBounds = false;
options.inPurgeable = true;// 设置图片可以被回收
conn.disconnect();
is.close();
conn = (HttpURLConnection) myFileUrl.openConnection();
conn.setDoInput(true);
conn.connect();
is = conn.getInputStream();
bitmap = BitmapFactory.decodeStream(is, null, options);
} else {
bitmap = BitmapFactory.decodeStream(is);
}
conn.disconnect();
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
public interface DisplayImageListener {
public void showImage(ImageView image, Bitmap bmp);
}
}
PicItem.java
package com.syncloadbmp;
public class PicItem {
public String mImageUrl;
public String mTitle;
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
</LinearLayout>
pic_item.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="@+id/image"
android:layout_width="100dp"
android:layout_height="60dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_margin="5dp"
android:layout_marginLeft="10dp" />
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dp" />
</RelativeLayout>
源码下载: SyncLoadBitmap