ListView图片优化(二)---弱引用关联---或者使用Volley下的NetworkImageView

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;
		}

	}

}

或者使用Volley下的NetworkImageView省略。。。。。。。。。。。。。。

你可能感兴趣的:(ListView图片优化(二)---弱引用关联---或者使用Volley下的NetworkImageView)