在自定义Adapter中,getView方法的convertView被重用导致的混乱
发一个异步图片加载控件。网上也有大把的异步网络加载图片的控件,但是有一个问题,异步加载会造成列表中的图片混乱,因为列表的每一项的View都可能被重用,异步加载的时候多个异步线程引用到了同一个View造成图片加载混乱。该控件解决这个问题:
import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.URL;import java.net.URLConnection;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.drawable.Drawable;import android.net.Uri;import android.os.AsyncTask;import android.util.AttributeSet;import android.widget.ImageView;/** * 异步图片控件 * 使用:new AsyncImageView().asyncLoadBitmapFromUrl("http://xxxx","缓存路径"){ * * @author gaoomei@gmail.com * @site http://obatu.sinaapp.com * @version 1.0 * @2011-12-3 */public class AsyncImageView extends ImageView {/** * 异步task加载器 */private AsyncLoadImage mAsyncLoad;/** * 下载回来的图片缓存存活时间,单位:秒(s),默认30分钟 */private long mCacheLiveTime = 1800;public AsyncImageView(Context context) {super(context);}public AsyncImageView(Context context, AttributeSet attrs) {super(context, attrs);}public AsyncImageView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}/** * */@Overridepublic void setImageDrawable(Drawable drawable) {if (mAsyncLoad != null) {mAsyncLoad.cancel(true);mAsyncLoad = null;}super.setImageDrawable(drawable);}/** * 重写下面几个设置图片资源的方法,目地是取消网络加载 */@Overridepublic void setImageResource(int resId) {cancelLoad();super.setImageResource(resId);}@Overridepublic void setImageURI(Uri uri) {cancelLoad();super.setImageURI(uri);}@Overridepublic void setImageBitmap(Bitmap bitmap) {cancelLoad();super.setImageBitmap(bitmap);}/** * 取消正在进行的异步task */public void cancelLoad() {if (mAsyncLoad != null) {mAsyncLoad.cancel(true);mAsyncLoad = null;}}/** * 设置图片存活时间 * * @param second * 存活时间,单位【秒】,如果等于0或null,则不缓存 */public void setCacheLiveTime(long second) {if (second == 0) {this.mCacheLiveTime = 0;} else if (second >= 0) {this.mCacheLiveTime = second * 1000;}}/** * 从网络异步加载 * * @param url * @param saveFileName */public void asyncLoadBitmapFromUrl(String url, String saveFileName) {if (mAsyncLoad != null) {mAsyncLoad.cancel(true);}// AsyncTask不可重用,所以每次重新实例mAsyncLoad = new AsyncLoadImage();mAsyncLoad.execute(url, saveFileName);}/** * 异步加载器 */private class AsyncLoadImage extends AsyncTask<String, Integer, Bitmap> {/** * 是否取消 */private boolean isCancel = false;@Overrideprotected Bitmap doInBackground(String... params) {if (isCancel) {return null;}String url = params[0];String fileName = params[1];try {return getBitmap(url, fileName);} catch (IOException e) {e.printStackTrace();}return null;}@Overrideprotected void onCancelled() {System.out.println("async load imgae cancel");isCancel = true;}@Overrideprotected void onPostExecute(Bitmap result) {if (!isCancel && result != null) {AsyncImageView.this.setImageBitmap(result);}}}/** * 下载图片 * * @param urlString * url下载地址 * @param fileName * 缓存文件路径 * @throws IOException */private Bitmap getBitmap(String urlString, String fileName)throws IOException {if (fileName == null || fileName.trim().isEmpty()) {InputStream input = getBitmapInputStreamFromUrl(urlString);return BitmapFactory.decodeStream(input);}File file = new File(fileName);if (!file.isFile()|| (mCacheLiveTime > 0 && (System.currentTimeMillis()- file.lastModified() > mCacheLiveTime))) {InputStream input = getBitmapInputStreamFromUrl(urlString);file = saveImage(input, fileName);// 如果文件结构创建失败,则直接从输入流解码图片if (file == null || !file.exists() || !file.canWrite()|| !file.canRead()) {return BitmapFactory.decodeStream(input);}}return BitmapFactory.decodeFile(file.getAbsolutePath());}/** * 下载图片,输入InputStream * * @param urlString * @return * @throws IOException */private InputStream getBitmapInputStreamFromUrl(String urlString)throws IOException {URL url = new URL(urlString);URLConnection connection = url.openConnection();connection.setConnectTimeout(25000);connection.setReadTimeout(90000);return connection.getInputStream();}/** * 从输入流保存图片到文件系统 * * @param fileName * @param input * @return */private File saveImage(InputStream input, String fileName) {if (fileName.trim().isEmpty() || input == null) {return null;}File file = new File(fileName);OutputStream output = null;try {file.getParentFile().mkdirs();if (file.exists() && file.isFile()) {file.delete();}if (!file.createNewFile()) {return null;}output = new FileOutputStream(file);byte[] buffer = new byte[4 * 1024];do {// 循环读取int numread = input.read(buffer);if (numread == -1) {break;}output.write(buffer, 0, numread);} while (true);output.flush();} catch (Exception e) {e.printStackTrace();} finally {try {output.close();} catch (IOException e) {e.printStackTrace();} catch (Exception e2) {e2.printStackTrace();}}return file;}}