ImageView中可以获取到它所对应的BitmapWorkerTask,而BitmapWorkerTask也可以获取到它所对应的ImageView。
BitmapWorkerTask指向ImageView的弱引用关联比较简单,就是在BitmapWorkerTask中加入一个构造函数,并在构造函数中要求传入ImageView这个参数。不过我们不再直接持有ImageView的引用,而是使用WeakReference对ImageView进行了一层包装,这样就OK了。
我们自定义了一个AsyncDrawable类并让它继承自BitmapDrawable,然后重写了AsyncDrawable的构造函数,在构造函数中要求把BitmapWorkerTask传入,然后在这里给它包装了一层弱引用。那么现在AsyncDrawable指向BitmapWorkerTask的关联已经有了,但是ImageView指向BitmapWorkerTask的关联还不存在,怎么办呢?很简单,让ImageView和AsyncDrawable再关联一下就可以了。可以看到,在getView()方法当中,我们调用了ImageView的setImageDrawable()方法把AsyncDrawable设置了进去,那么ImageView就可以通过getDrawable()方法获取到和它关联的AsyncDrawable,然后再借助AsyncDrawable就可以获取到BitmapWorkerTask了。
package com.example.listviewyouhua; import java.lang.ref.WeakReference; import java.net.HttpURLConnection; import java.net.URL; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.support.v4.util.LruCache; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.ListView; public class ImageAdapter extends ArrayAdapter<String> { private ListView mListView; /** * 图片缓存技术的核心类,用于缓存所有下载好的图片,在程序内存达到设定值时会将最少最近使用的图片移除掉。 */ private LruCache<String, BitmapDrawable> mMemoryCache; // 加载的默认图片 private Bitmap mLoadingBitmap; public ImageAdapter(Context context, int resource, String[] objects) { super(context, resource, objects); mLoadingBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher); // 获取应用程序最大可用内存 int maxMemory = (int) Runtime.getRuntime().maxMemory(); int cacheSize = maxMemory / 8; mMemoryCache = new LruCache<String, BitmapDrawable>(cacheSize) { @Override protected int sizeOf(String key, BitmapDrawable drawable) { return drawable.getBitmap().getByteCount(); } }; } @Override public View getView(int position, View convertView, ViewGroup parent) { if (mListView == null) { mListView = (ListView) parent; } String url = getItem(position); View view; if (convertView == null) { view = LayoutInflater.from(getContext()).inflate( R.layout.image_item, null); } else { view = convertView; } ImageView image = (ImageView) view.findViewById(R.id.image); BitmapDrawable drawable = getBitmapFromMemoryCache(url); if (drawable != null) { image.setImageDrawable(drawable); } else if (cancelPotentialWork(url, image)) { BitmapWorkerTask task = new BitmapWorkerTask(image); AsyncDrawable asyncDrawable = new AsyncDrawable(getContext() .getResources(), mLoadingBitmap, task); image.setImageDrawable(asyncDrawable); task.execute(url); } return view; } /** * 取消掉后台的潜在任务,当认为当前ImageView存在着一个另外图片请求任务时 ,则把它取消掉并返回true,否则返回false。 */ public boolean cancelPotentialWork(String url, ImageView imageView) { BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); if (bitmapWorkerTask != null) { String imageUrl = bitmapWorkerTask.imageUrl; if (imageUrl == null || !imageUrl.equals(url)) { bitmapWorkerTask.cancel(true); } else { return false; } } return true; } /** * 获取传入的ImageView它所对应的BitmapWorkerTask。 */ private BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) { if (imageView != null) { Drawable drawable = imageView.getDrawable(); if (drawable instanceof AsyncDrawable) { AsyncDrawable asyncDrawable = (AsyncDrawable) drawable; return asyncDrawable.getBitmapWorkerTask(); } } return null; } /** * 自定义的一个Drawable,让这个Drawable持有BitmapWorkerTask的弱引用。 */ class AsyncDrawable extends BitmapDrawable { private WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference; public AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) { super(res, bitmap); bitmapWorkerTaskReference = new WeakReference<BitmapWorkerTask>( bitmapWorkerTask); } public BitmapWorkerTask getBitmapWorkerTask() { return bitmapWorkerTaskReference.get(); } } /** * 将一张图片存储到LruCache中。 * * @param key * LruCache的键,这里传入图片的URL地址。 * @param drawable * LruCache的值,这里传入从网络上下载的BitmapDrawable对象。 */ public void addBitmapToMemoryCache(String key, BitmapDrawable drawable) { if (getBitmapFromMemoryCache(key) == null) { mMemoryCache.put(key, drawable); } } /** * 从LruCache中获取一张图片,如果不存在就返回null。 * * @param key * LruCache的键,这里传入图片的URL地址。 * @return 对应传入键的BitmapDrawable对象,或者null。 */ public BitmapDrawable getBitmapFromMemoryCache(String key) { return mMemoryCache.get(key); } /** * 异步下载图片的任务。 * * @author guolin */ class BitmapWorkerTask extends AsyncTask<String, Void, BitmapDrawable> { String imageUrl; /** * 就是在BitmapWorkerTask中加入一个构造函数,并在构造函数中要求传入ImageView这个参数。 * 不过我们不再直接持有ImageView的引用,而是使用WeakReference对ImageView进行了一层包装 */ private WeakReference<ImageView> imageViewReference; public BitmapWorkerTask(ImageView imageView) { imageViewReference = new WeakReference<ImageView>(imageView); } @Override protected BitmapDrawable doInBackground(String... params) { imageUrl = params[0]; // 在后台开始下载图片 Bitmap bitmap = downloadBitmap(imageUrl); BitmapDrawable drawable = new BitmapDrawable(getContext() .getResources(), bitmap); addBitmapToMemoryCache(imageUrl, drawable); return drawable; } @Override protected void onPostExecute(BitmapDrawable drawable) { //获取当前BitmapWorkerTask所关联的ImageView ImageView imageView = getAttachedImageView(); if (imageView != null && drawable != null) { imageView.setImageDrawable(drawable); } } /** * 获取当前BitmapWorkerTask所关联的ImageView。 */ private ImageView getAttachedImageView() { ImageView imageView = imageViewReference.get(); //获取传入的ImageView它所对应的BitmapWorkerTask。 BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); if (this == bitmapWorkerTask) { return imageView; } return null; } /** * 建立HTTP请求,并获取Bitmap对象。 * * @param imageUrl * 图片的URL地址 * @return 解析后的Bitmap对象 */ private Bitmap downloadBitmap(String imageUrl) { Bitmap bitmap = null; HttpURLConnection con = null; try { URL url = new URL(imageUrl); con = (HttpURLConnection) url.openConnection(); con.setConnectTimeout(5 * 1000); con.setReadTimeout(10 * 1000); bitmap = BitmapFactory.decodeStream(con.getInputStream()); } catch (Exception e) { e.printStackTrace(); } finally { if (con != null) { con.disconnect(); } } return bitmap; } } }