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

在《自己动手写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();
	}
}

源码下载

时间: 2024-12-18 14:19:35

自己动手写android图片异步加载库(二)的相关文章

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

尊重他人劳动成果,转载请说明出处:http://blog.csdn.net/bingospunky/article/details/44344085 接触android有半年了,关于图片异步加载,一直只用别人的框架,虽然特别方便,但是始终未见识到图片异步加载的庐山真面目.最近比较悠闲,研究一些高大上的东西.在这篇文章总结一下我对图片异步加载的一些学习心得. 图片加载最重要的无非就是内存和线程.大家都知道关于内存溢出一般的解决方案就是LruCache,在我的这个demo里我只要使用SoftRefe

Android图片异步加载之Android-Universal-Image-Loader类库的使用

Android开发中我们会经常遇到图片过多或操作不当造成Out of Memory异常,有时虽然是解决了这个问题但却会影响程序的运行效率,例如:当用户在快速滑动滚动条的过程中,我们程序在仍在艰难的加载服务器端的图片,这样给用户造成了极不好的体验.其实网络上关于图片的异步加载和缓存的讲解很多,但是其实,写一个这方面的程序还是比较麻烦的,要考虑多线程,缓存,内存溢出等很多方面,针对这一广大开发者都会遇到的问题,一些牛人们已经帮我们解决了这一问题,今天我为大家介绍一款很流行的开源类库,可以很很好的解决

Android图片异步加载之Android-Universal-Image-Loader

将近一个月没有更新博客了,由于这段时间以来准备毕业论文等各种事务缠身,一直没有时间和精力沉下来继续学习和整理一些东西.最近刚刚恢复到正轨,正好这两天看了下Android上关于图片异步加载的开源项目,就顺便整理记录下来,作为这一个多月来博客的重新开火做饭吧.从今天起我会陆续恢复博客的更新,也希望大家继续支持. 今天要介绍的是Github上一个使用非常广泛的图片异步加载库Android-Universal-Image-Loader,该项目的功能十分强大,可以说是我见过的目前功能最全.性能最优的图片异

Android图片异步加载之Android-Universal-Image-Loader(转)

今天要介绍的是Github上一个使用非常广泛的图片异步加载库Android-Universal-Image-Loader,该项目的功能十分强大,可以说是我见过的目前功能最全.性能最优的图片异步加载解决方案.做Android的同学都知道,Android加载大量图片时,由于系统分配给图片加载的内存大小有限,所以,如果加载图片量非常大的话容易报OOM异常,关于这个异常已经有不少解决方案了,我就不赘述.下面就简要介绍下这个开源项目的主要功能和使用: 一.功能概要 多线程图片加载: 灵活更改ImageLo

Android图片异步加载

原:http://www.cnblogs.com/angeldevil/archive/2012/09/16/2687174.html 相关:https://github.com/nostra13/Android-Universal-Image-Loader 开发Android程序,一般情况下都会有两个操作,图片的异步加载与缓存,而图片的异步加载大都是从网络读取图片(还有生成本地图片缩略图等操作),为了减少网络操作,加快图片加载速度就需要对图片进行缓存,所以网上的好多图片异步加载方法都是与图片的

Android图片异步加载框架Android-Universal-Image-Loader

Android-Universal-Image-Loader是一个图片异步加载,缓存和显示的框架.这个框架已经被很多开发者所使用,是最常用的几个Android开源项目之一,主流的应用,随便反编译几个,都可以见到它的身影.淘宝,天猫,Facebook,京东商城等都用到了这个项目. 该项目的Github地址链接:https://github.com/nostra13/Android-Universal-Image-Loader 运行流程: 每一个图片的加载和显示任务都运行在独立的线程中,除非这个图片

Android图片异步加载框架Universal Image Loader的源码分析

项目地址:https://github.com/nostra13/android-universal-image-loader 1. 功能介绍 1.1 Android Universal Image Loader Android Universal Image Loader 是一个强大的.可高度定制的图片缓存,本文简称为UIL. 简单的说 UIL 就做了一件事--获取图片并显示在相应的控件上. 1.2 基本使用 1.2.1 初始化 添加完依赖后在Application或Activity中初始化I

Android-Universal-Image-Loader 图片异步加载类库的使用(超详细配置)

这个图片异步加载并缓存的类已经被很多开发者所使用,是最常用的几个开源库之一,主流的应用,随便反编译几个火的项目,都可以见到它的身影. 可是有的人并不知道如何去使用这库如何进行配置,网上查到的信息对于刚接触的人来说可能太少了,下面我就把我使用过程中所知道的写了下来,希望可以帮助自己和别人更深入了解这个库的使用和配置. GITHUB上的下载路径为:https://github.com/nostra13/Android-Universal-Image-Loader ,下载最新的库文件,并且导入到项目的

【转】Android-Universal-Image-Loader 图片异步加载类库的使用(超详细配置)

Android-Universal-Image-Loader 原文地址:http://blog.csdn.net/vipzjyno1/article/details/23206387 这个图片异步加载并缓存的类已经被很多开发者所使用,是最常用的几个开源库之一,主流的应用,随便反编译几个火的项目,都可以见到它的身影. 可是有的人并不知道如何去使用这库如何进行配置,网上查到的信息对于刚接触的人来说可能太少了,下面我就把我使用过程中所知道的写了下来,希望可以帮助自己和别人更深入了解这个库的使用和配置.