使用Android新式LruCache缓存图片,基于线程池异步加载图片

简介: import java.io.BufferedInputStream;import java.io.ByteArrayOutputStream;import java.
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
import android.support.v4.util.LruCache;
import android.util.Log;
import android.widget.ImageView;

/*
 * 使用Android新式LruCache缓存图片,基于线程池异步加载图片。 
 * 基本思路:开辟一个线程池下载网络图片,同时创建一个LruCache作为Android内存缓存混存图片。
 * 上层应用传递过来一个URL要求从该URL下载图片时,首先检查LruCache中是否存在以该URL为索引的缓存图片,
 * 若有,则直接从缓存中读出来返回给上层应用;若没有,此时再开辟线程下载,下载完成后将此bitmap埋入缓存。
 * 备注:图片的url作为缓存图片时LruCache的 Key。
 * LruCache在内存中的缓存模型为<K,V>。
 */

public class AsyncImageLoader {

	private ExecutorService pool;
	private Handler handler;
	private ImageLoadedListener listener;

	private final int WHAT = 0xe001;

	// 默认的线程池容量
	private int DEFAULT_TASK_NUMBER = 10;

	// 网络超时时间:30秒
	private static int TIMEOUT = 30 * 1000;

	private LruCache<String, Bitmap> mMemoryCache;
	// 4MB缓存大小
	private final int CACHE_SIZE = 4 * 1024 * 1024;

	public AsyncImageLoader(int asyncTaskNumber) {
		initialization(asyncTaskNumber);
	}

	public AsyncImageLoader() {
		// 默认的构造函数初始化线程池容量为:TASK_NUMBER
		initialization(DEFAULT_TASK_NUMBER);
	}

	// 初始化
	private void initialization(int asyncTaskNumber) {
		mMemoryCache = new LruCache<String, Bitmap>(CACHE_SIZE) {
			@Override
			protected int sizeOf(String key, Bitmap value) {
				return value.getRowBytes() * value.getHeight();
			}
		};

		// 创建容量为 asyncTaskNumber 的线程池。
		pool = Executors.newFixedThreadPool(asyncTaskNumber);

		handler = new Handler() {
			@Override
			public void handleMessage(Message message) {
				switch (message.what) {
				case WHAT:
					listener.imageLoaded((Bitmap) message.obj);
				}
			}
		};
	}

	
	// 异步设置一个ImagView的Bitmap(该ImageView的Bitmap从网络加载)
	// 该方法为public,作为该工具类的外部调用接口。
	public void asyncSetImageBitmap(String url, final ImageView view) {
		download(url, new ImageLoadedListener() {
			@Override
			public void imageLoaded(Bitmap bitmap) {
				view.setImageBitmap(bitmap);
			}
		});
	}

	// 异步的从一个URL下载一个Bitmap。
	// 下载成功后,回调imageLoaded(Bitmap bitmap, String url);
	// 该方法为public,作为该工具类的外部调用接口。
	public void download(String url, ImageLoadedListener listener) {
		this.listener = listener;

		// 首先从缓存中检查是否存在以url为key的bitmap。
		// 若有,则直接从缓存中读取使用,不再使用线程重复加载。
		Bitmap bmp = mMemoryCache.get(url);
		if (bmp != null) {
			Log.d("读取缓存", url + " 已经缓存,无须重复下载!");
			sendResult(bmp);
			return;
		}

		Thread t = new DownloadThread(url);
		pool.execute(t);
	}
	

	// 开辟一个下载线程
	private class DownloadThread extends Thread {

		private String url;

		public DownloadThread(String url) {
			this.url = url;
		}

		@Override
		public void run() {
			Bitmap bmp = loadBitmapFromURL(url);

			// 将新的bitmap埋入缓存
			mMemoryCache.put(url, bmp);

			sendResult(bmp);
		}
	}

	// 发送消息通知:bitmap已经下载完成。
	private void sendResult(Bitmap bitmap) {
		Message message = handler.obtainMessage();
		message.what = WHAT;
		message.obj = bitmap;
		handler.sendMessage(message);
	}

	// 回调函数
	public interface ImageLoadedListener {
		public void imageLoaded(Bitmap bitmap);
	}

	// 给定一个URL,从这个URL下载Bitmap
	public static Bitmap loadBitmapFromURL(String url) {
		if (!url.contains("http://")) {
			url = "http://" + url;
		}

		Log.d("线程:" + Thread.currentThread().getId(), "开始下载: " + url);

		Bitmap bmp = null;
		try {
			byte[] imageBytes = loadRawDataFromURL(url);
			bmp = BitmapFactory.decodeByteArray(imageBytes, 0,
					imageBytes.length);
		} catch (Exception e) {
			e.printStackTrace();
		}

		return bmp;
	}

	// 给定一个URL,从这个URL下载原始数据块。
	public static byte[] loadRawDataFromURL(String u) throws Exception {
		URL url = new URL(u);
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		// 配置基础网络链接参数
		conn.setConnectTimeout(TIMEOUT);
		conn.setReadTimeout(TIMEOUT);

		InputStream is = conn.getInputStream();
		BufferedInputStream bis = new BufferedInputStream(is);

		ByteArrayOutputStream baos = new ByteArrayOutputStream();

		final int BUFFER_SIZE = 1024 * 5;
		final int EOF = -1;

		int c;
		byte[] buf = new byte[BUFFER_SIZE];

		while (true) {
			c = bis.read(buf);
			if (c == EOF)
				break;

			baos.write(buf, 0, c);
		}

		conn.disconnect();
		is.close();

		byte[] data = baos.toByteArray();
		baos.flush();

		return data;
	}
}

相关文章
|
1月前
|
Java 调度 Android开发
构建高效Android应用:探究Kotlin多线程编程
【2月更文挑战第17天】 在现代移动开发领域,性能优化一直是开发者关注的焦点。特别是在Android平台上,合理利用多线程技术可以显著提升应用程序的响应性和用户体验。本文将深入探讨使用Kotlin进行Android多线程编程的策略与实践,旨在为开发者提供系统化的解决方案和性能提升技巧。我们将从基础概念入手,逐步介绍高级特性,并通过实际案例分析如何有效利用Kotlin协程、线程池以及异步任务处理机制来构建一个更加高效的Android应用。
41 4
|
1月前
|
API 数据库 Android开发
构建高效Android应用:探究Kotlin多线程优化策略
【2月更文挑战第14天】随着移动设备性能的日益强大,用户对应用程序的响应速度和流畅性要求越来越高。在Android开发中,合理利用多线程技术是提升应用性能的关键手段之一。Kotlin作为一种现代的编程语言,其协程特性为开发者提供了更为简洁高效的多线程处理方式。本文将深入探讨使用Kotlin进行Android多线程编程的最佳实践,包括协程的基本概念、优势以及在实际项目中的应用场景和性能优化技巧,旨在帮助开发者构建更加高效稳定的Android应用。
|
3月前
|
Java 调度 数据库
Android 性能优化: 如何进行多线程编程以提高应用性能?
Android 性能优化: 如何进行多线程编程以提高应用性能?
47 0
|
13天前
|
Java API 调度
安卓多线程和并发处理:提高应用效率
【4月更文挑战第13天】本文探讨了安卓应用中多线程和并发处理的优化方法,包括使用Thread、AsyncTask、Loader、IntentService、JobScheduler、WorkManager以及线程池。此外,还介绍了RxJava和Kotlin协程作为异步编程工具。理解并恰当运用这些技术能提升应用效率,避免UI卡顿,确保良好用户体验。随着安卓技术发展,更高级的异步处理工具将助力开发者构建高性能应用。
|
4月前
|
XML JSON Java
Android App开发即时通信中通过SocketIO在客户端与服务端间传输文本和图片的讲解及实战(超详细 附源码)
Android App开发即时通信中通过SocketIO在客户端与服务端间传输文本和图片的讲解及实战(超详细 附源码)
72 0
|
24天前
|
安全 Linux API
Android进程与线程
Android进程与线程
18 0
|
24天前
|
Android开发
Android保存图片到相册(适配android 10以下及以上)
Android保存图片到相册(适配android 10以下及以上)
22 1
|
1月前
|
Java Android开发 开发者
构建高效Android应用:探究Kotlin多线程优化策略
【2月更文挑战第17天】 随着移动设备性能的不断提升,用户对应用的响应速度和稳定性要求越来越高。在Android开发中,Kotlin语言以其简洁、安全的特点受到开发者青睐。然而,面对复杂的多线程任务,如何有效利用Kotlin进行优化,以提升应用性能,是本文探讨的重点。通过分析Kotlin并发工具的使用场景与限制,结合实例演示其在Android开发中的实践,旨在为开发者提供实用的多线程处理指南。
|
4月前
|
缓存 NoSQL Java
springboot集成图片验证+redis缓存一步到位2
springboot集成图片验证+redis缓存一步到位2
|
4月前
|
缓存 NoSQL Java
springboot集成图片验证+redis缓存一步到位
springboot集成图片验证+redis缓存一步到位

热门文章

最新文章