码迷,mamicode.com
首页 > 移动开发 > 详细

自己动手写android图片异步加载库(二)

时间:2015-04-27 15:21:17      阅读:158      评论:0      收藏:0      [点我收藏+]

标签:图片异步加载   线程池   java信号量   imageloader   

    在《自己动手写android图片异步加载库》系列的第一篇文章中,主要是学习了使用ReferenceQueue来实现一个内存缓存。在这篇文章中主要是介绍在下载很多图片是怎么控制线程和队列。在这版代码里,加入信号量和队列,可以控制下载任务的顺序、可以控制暂停和结束。

代码A:ImageLoader.java

/**
 * 图片加载工具类
 * 
 * @author qingtian
 * @blog http://blog.csdn.net/bingoSpunky
 */
@SuppressLint("HandlerLeak")
public class ImageLoader {

	private int flag = 0;
	public static int FLAG_FINISHED_INIT_SECOND_THREAD = 0X1;
	
	
	private static final int DEFAULT_THREAD_COUNT = 2;
	private static final int SUCCESS = 1;
	private static final int FAILED = 0;

	// config
	public int configLoadingImage;// 正在现在时显示的图片id
	public int configFailedImage;// 下载失败时显示的资源id
	public Type configType = Type.LIFO;// 队列的调度方式

	private ExecutorService threadPool;// 线程池
	private Tasks task;// 管理任务的队列

	// 图片缓存
	private LruCache<String, Bitmap> cache;

	private Handler mainHandler;// 主线程的handler,修改view

	private Handler secondHandler;//
	private volatile Semaphore secondSemaphore;// 信号量控制第二条线程发送的正在执行且没执行完的线程的数量==线程池的数量


	public ImageLoader() {
		this(DEFAULT_THREAD_COUNT);
	}

	public ImageLoader(int threadNum) {
		
		task = new Tasks();

		new Thread() {
			public void run() {
				Looper.prepare();

				secondHandler = new Handler() {
					public void handleMessage(android.os.Message msg) {

						try {
							secondSemaphore.acquire();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}

						threadPool.execute(task.getTask(configType));

					};
				};
				flag |= FLAG_FINISHED_INIT_SECOND_THREAD;
				task.mSemaphore.release();

				Looper.loop();
			};
		}.start();

		mainHandler = new Handler() {

			@Override
			public void handleMessage(Message msg) {
				ImgBeanHolder holder;
				switch (msg.what) {
				case SUCCESS:
					holder = (ImgBeanHolder) msg.obj;
					ImageView imageView = holder.imageView;
					Bitmap bm = holder.bitmap;
					String uri = holder.uri;
					Object tag = imageView.getTag();
					if (holder!=null&&holder.listener != null) {
						if (tag != null && tag.toString().equals(uri)) {
							holder.listener.onSuccess(imageView, true, bm, uri);
						} else {
							holder.listener.onSuccess(imageView, false, bm, uri);
						}
						LogUtils.d("加载失败    加载图片    uri:"+holder.uri);
					}
					break;
				case FAILED:
					holder = (ImgBeanHolder) msg.obj;
					if (holder.listener != null) {
						holder.listener.onFailed();
						LogUtils.d("加载成功    加载图片    uri:"+holder.uri);
					}
					break;
				}

			}

		};

		threadPool = new ThreadPoolExecutor(threadNum, threadNum, 0,
				TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>());
		secondSemaphore = new Semaphore(threadNum);

		int maxMemory = (int) Runtime.getRuntime().maxMemory();
		cache = new LruCache<String, Bitmap>(maxMemory / 8) {
			// 测量Bitmap的大小
			@Override
			protected int sizeOf(String key, Bitmap value) {
				return value.getRowBytes() * value.getHeight();
			}
		};

	}

	public void display(ImageView iv, String uri) {
		display(iv, uri, new SimpleImageLoaderListener());
	}

	public void display(final ImageView iv, final String uri,
			final ImageLoaderListener imageLoaderListener)
			throws RuntimeException {

		if (imageLoaderListener == null) {
			throw new RuntimeException("imageLoaderListener不能为空");
		}

		iv.setTag(uri);

		showDefalutImage(iv);

		task.addTask(flag, new Runnable() {
			@Override
			public void run() {

				LogUtils.d("开始    加载图片    uri:"+uri);
				
				Bitmap bm = cache.get(uri);
				if (bm != null) {
					LogUtils.d("在内存缓存    加载图片    uri:"+uri);
					sendMessageToMainHandler(SUCCESS, bm, iv, uri,
							imageLoaderListener);
				} else {

					ImageSize imageSize = ImageViewUtil.getImageViewWidth(iv);

					LogUtils.d("通过网络    加载图片     uri:"+uri);
					bm = BitmapUtil.decodeSampledBitmapFromResource(uri,
							imageSize.width, imageSize.height);
					// bm = BitmapUtil.getImageBitmap(uri);

					if (bm != null) {
						cache.put(uri, bm);
						sendMessageToMainHandler(SUCCESS, bm, iv, uri,
								imageLoaderListener);
					} else {
						sendMessageToMainHandler(FAILED, bm, iv, uri,
								imageLoaderListener);
					}

				}
				secondSemaphore.release();
			}
		});
		secondHandler.sendEmptyMessage(0x123);

	}
	
	@SuppressWarnings("deprecation")
	private static BitmapDrawable mBitmapDrawable = new BitmapDrawable();
	public void showDefalutImage(ImageView iv){
		if (configLoadingImage != 0) {
			iv.setImageResource(configLoadingImage);
		}else{
			iv.setImageDrawable(mBitmapDrawable);
		}
	}

	public void stop() {
		task.stop();
	}

	public void restart() {
		task.start();
	}

	public void cancel() {
		task.cancel();
	}

	/**
	 * 向主线程的handler发送message
	 */
	private void sendMessageToMainHandler(int what, Bitmap bm, ImageView iv,
			String uri, ImageLoaderListener imageLoaderListener) {
		ImgBeanHolder holder = new ImgBeanHolder();
		holder.bitmap = bm;
		holder.imageView = iv;
		holder.uri = uri;
		holder.listener = imageLoaderListener;
		Message msg = Message.obtain();
		msg.what = what;
		msg.obj = holder;
		mainHandler.sendMessage(msg);
	}

	public class ImgBeanHolder {
		Bitmap bitmap;
		ImageView imageView;
		String uri;
		ImageLoaderListener listener;
	}

}

代码B:Tasks.java

public class Tasks {
	
	public boolean starting = true;
	
	public enum Type
	{
		FIFO, LIFO
	}

	/**
	 * 引入一个值为1的信号量,防止mPoolThreadHander未初始化完成
	 */
	public volatile Semaphore mSemaphore = new Semaphore(0);

	/**
	 * 任务队列
	 */
	private LinkedList<Runnable> mTasks;
	
	
	public Tasks() {
		mTasks = new LinkedList<Runnable>();
	}

	public synchronized void addTask(int flag, Runnable runnable) {
		try {
			// 请求信号量,防止mPoolThreadHander为null
			if ((flag & ImageLoader.FLAG_FINISHED_INIT_SECOND_THREAD) == 0)
				mSemaphore.acquire();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		mTasks.add(runnable);
	}

	public volatile Semaphore startingSemaphore = new Semaphore(0);
	/**
	 * 取出一个任务
	 */
	public synchronized Runnable getTask(Type type) {
		if(!starting){
			try {
				LogUtils.d("wait()");
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		if (type == Type.FIFO) {
			return mTasks.removeFirst();
		} else if (type == Type.LIFO) {
			return mTasks.removeLast();
		}
		return null;
	}
	
	public synchronized void start(){
		if(!starting){
			starting = true;
			this.notify();
			LogUtils.d("start notify()");
		}
	}
	public synchronized void stop(){
		if(starting){
			LogUtils.d("stop()");
			starting = false;
		}
	}
	
	/**
	 * 取消所有任务
	 */
	public synchronized void cancel(){
		mTasks.clear();
	}
}


源码下载



自己动手写android图片异步加载库(二)

标签:图片异步加载   线程池   java信号量   imageloader   

原文地址:http://blog.csdn.net/bingospunky/article/details/45309099

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!