Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 自己動手寫android圖片異步加載庫(二)

自己動手寫android圖片異步加載庫(二)

日期:2017/2/23 15:58:57      編輯:關於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 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());
		secondSemaphore = new Semaphore(threadNum);

		int maxMemory = (int) Runtime.getRuntime().maxMemory();
		cache = new LruCache(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 mTasks;
	
	
	public Tasks() {
		mTasks = new LinkedList();
	}

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

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved