android异步图片加载三之handler+线程池+消息队列模式+缓存

简介:

http://blog.csdn.net/soesa/article/details/7787922

假象现在有这样一个需求:

      一个微博客户端或者多媒体客户端需要从服务端拉取一些数据,该数据中包含了很多图片,如果不用异步加载方式,可能会使主线程阻塞导致ANR异常,但是异步加载后如果每次都通过网络去下载图片,性能上会差很多,而且也会浪费流量,导致用户的不满,故现在增加一个缓存用来存储图片,缓存中包含内存存储和sdcard存储。先从缓存中去,在缓存中先从内存中取出,如果内存中没有再从sdcard去,如果sdcard中存在则直接返回该图片资源并放入内存中,如果两者都没有则从网络上下载,下载后并放入sdcard中供下次使用,这样就节约了资源开销,下面是主要代码:

PicManager(用来处理图片的操作):

[java]  view plain copy
  1. public class PicManager {  
  2.   
  3.     private Map<String,SoftReference<Bitmap>> imgCache ;  
  4.     private Context ctx;  
  5.       
  6.     public PicManager(Map<String,SoftReference<Bitmap>> imgCache,Context ctx) {  
  7.         this.ctx = ctx;  
  8.         this.imgCache = imgCache;  
  9.     }  
  10.       
  11.       
  12.     /** 
  13.      * 从网络上下载 
  14.      * @param url 
  15.      * @return 
  16.      */  
  17.     public Bitmap getBitMapFromUrl(String url) {  
  18.         Bitmap bitmap = null;  
  19.         URL u =null;  
  20.         HttpURLConnection conn = null;  
  21.         InputStream is = null;  
  22.         try {  
  23.             u = new URL(url);  
  24.             conn = (HttpURLConnection)u.openConnection();  
  25.             is = conn.getInputStream();  
  26.             bitmap = BitmapFactory.decodeStream(is);  
  27.         } catch (Exception e) {  
  28.             e.printStackTrace();  
  29.         }  
  30.         return bitmap;  
  31.     }  
  32.       
  33.     /** 
  34.      * 从文件中读取 
  35.      * @return 
  36.      * @throws Exception  
  37.      */  
  38.     private Bitmap getBitMapFromSDCard(String url) throws Exception {  
  39.         Bitmap bitmap = null;  
  40.         String filename = MD5Util.getMD5(url);  
  41.         FileInputStream fis = ctx.openFileInput(filename);  
  42.         bitmap = BitmapFactory.decodeStream(fis);  
  43.         return bitmap;  
  44.     }  
  45.       
  46.     /** 
  47.      * 从缓存中读取 
  48.      * @param url 
  49.      * @return 
  50.      * @throws Exception  
  51.      */  
  52.     public Bitmap getImgFromCache(String url) throws Exception {  
  53.         Bitmap bitmap = null;  
  54.         //从内存中读取  
  55.         if(imgCache.containsKey(url)) {  
  56.             synchronized (imgCache) {  
  57.                 SoftReference<Bitmap> bitmapReference = imgCache.get(url);  
  58.                 if(null != bitmapReference) {  
  59.                     bitmap = bitmapReference.get();  
  60.                 }  
  61.             }  
  62.         } else {//否则从文件中读取  
  63.             bitmap = getBitMapFromSDCard(url);  
  64.             //将图片保存进内存中  
  65.             imgCache.put(url, new SoftReference<Bitmap>(bitmap));  
  66.         }  
  67.         return bitmap;  
  68.     }  
  69.       
  70.     /** 
  71.      * 将图片写入sdcard中 
  72.      * @param bitmap 
  73.      * @param url 
  74.      * @throws Exception 
  75.      */  
  76.     public void writePic2SDCard(Bitmap bitmap,String url) throws Exception {  
  77.         String filename = MD5Util.getMD5(url);  
  78.         FileOutputStream fos = ctx.openFileOutput(filename, ctx.MODE_APPEND);  
  79.         byte[] bitmapByte = PictureUtil.bitmap2Byte(bitmap);  
  80.         ByteArrayInputStream bis = new ByteArrayInputStream(bitmapByte);  
  81.         int len = 0;  
  82.         byte[] b = new byte[bis.available()];  
  83.         while((len = bis.read(b)) != -1) {  
  84.             fos.write(b, 0, len);  
  85.         }  
  86.         if(null != bis) {  
  87.             bis.close();  
  88.         }  
  89.         if(null != fos) {  
  90.             fos.close();  
  91.         }  
  92.     }  
  93. }  

 ImgLoader(用来加在图片):


[java]  view plain copy
  1. public class ImgLoader {  
  2.   
  3.     private Map<String,SoftReference<Bitmap>> imgCache = new HashMap<String,SoftReference<Bitmap>>();  
  4.     private Context ctx;  
  5.       
  6.     public ImgLoader(Context ctx) {  
  7.         this.ctx = ctx;  
  8.     }  
  9.       
  10.     private PicManager manager = new PicManager(imgCache,ctx);  
  11.     private Handler handler = new Handler();  
  12.       
  13.       
  14.     private ExecutorService threadPool = Executors.newFixedThreadPool(5);  
  15.       
  16.     public Bitmap loadImg(final String url,final ImgCallback callback) {  
  17.           
  18.         //先从缓存中读取图片资源  
  19.         Bitmap bitmap = null;  
  20.         try {  
  21.             bitmap = manager.getImgFromCache(url);;  
  22.               
  23.             if(null == bitmap) {  
  24.                 //开启线程从网络上下载  
  25.                 threadPool.submit(new Runnable() {//submit方法确保下载是从线程池中的线程执行  
  26.                     @Override  
  27.                     public void run() {  
  28.                         final Bitmap bitmapFromUrl = manager.getBitMapFromUrl(url);  
  29.                         try {  
  30.                             manager.writePic2SDCard(bitmapFromUrl,url);  
  31.                         } catch (Exception e) {  
  32.                             e.printStackTrace();  
  33.                         }  
  34.                         handler.post(new Runnable() {  
  35.                             @Override  
  36.                             public void run() {  
  37.                                 callback.refresh(bitmapFromUrl);  
  38.                             }  
  39.                         });  
  40.                     }  
  41.                 });  
  42.             } else {  
  43.                   
  44.             }  
  45.         } catch (Exception e) {  
  46.             e.printStackTrace();  
  47.         }  
  48.         return bitmap;  
  49.     }  
  50.       
  51. }  

 ImgCallback callback是一个接口,用来刷新界面


[java]  view plain copy
  1. public interface ImgCallback {  
  2.   
  3.       
  4.     public void refresh(Bitmap bitmap);  
  5. }  

相关文章
|
缓存 安全 算法
Java面试题:如何通过JVM参数调整GC行为以优化应用性能?如何使用synchronized和volatile关键字解决并发问题?如何使用ConcurrentHashMap实现线程安全的缓存?
Java面试题:如何通过JVM参数调整GC行为以优化应用性能?如何使用synchronized和volatile关键字解决并发问题?如何使用ConcurrentHashMap实现线程安全的缓存?
260 0
|
缓存 安全 Java
7张图带你轻松理解Java 线程安全,java缓存机制面试
7张图带你轻松理解Java 线程安全,java缓存机制面试
|
存储 缓存 NoSQL
大数据-38 Redis 高并发下的分布式缓存 Redis简介 缓存场景 读写模式 旁路模式 穿透模式 缓存模式 基本概念等
大数据-38 Redis 高并发下的分布式缓存 Redis简介 缓存场景 读写模式 旁路模式 穿透模式 缓存模式 基本概念等
526 4
|
存储 Java 数据库连接
Android Java开发异步
【6月更文挑战第15天】
183 8
|
JSON Java API
【Android】使用 Retrofit2 发送异步网络请求的简单案例
**摘要:** Retrofit是Android和Java的HTTP客户端库,简化了RESTful API交互。它通过Java接口定义HTTP请求,并提供注解管理参数、HTTP方法等。要使用Retrofit,首先在AndroidManifest.xml中添加`INTERNET`权限,然后在`build.gradle`中引入Retrofit和Gson依赖。创建服务器响应数据类和描述接口的接口,如`Result`和`Api`。通过Retrofit.Builder配置基础URL并构建实例,之后调用接口方法创建Call对象并发送异步请求。
693 1
|
Android开发 Kotlin
Android面试题 之 Kotlin DataBinding 图片加载和绑定RecyclerView
本文介绍了如何在Android中使用DataBinding和BindingAdapter。示例展示了如何创建`MyBindingAdapter`,包含一个`setImage`方法来设置ImageView的图片。布局文件使用`&lt;data&gt;`标签定义变量,并通过`app:image`调用BindingAdapter。在Activity中设置变量值传递给Adapter处理。此外,还展示了如何在RecyclerView的Adapter中使用DataBinding,如`MyAdapter`,在子布局`item.xml`中绑定User对象到视图。关注公众号AntDream阅读更多内容。
334 1
|
Android开发
40. 【Android教程】AsyncTask:异步任务
40. 【Android教程】AsyncTask:异步任务
558 2
|
缓存 NoSQL 中间件
【后端面经】【缓存】36|Redis 单线程:为什么 Redis 用单线程而 Memcached 用多线程?epoll、poll和select + Reactor模式
【5月更文挑战第19天】`epoll`、`poll`和`select`是Linux下多路复用IO的三种方式。`select`需要主动调用检查文件描述符,而`epoll`能实现回调,即使不调用`epoll_wait`也能处理就绪事件。`poll`与`select`类似,但支持更多文件描述符。面试时,重点讲解`epoll`的高效性和`Reactor`模式,该模式包括一个分发器和多个处理器,用于处理连接和读写事件。Redis采用单线程模型结合`epoll`的Reactor模式,确保高性能。在Redis 6.0后引入多线程,但基本原理保持不变。
311 2
|
canal 缓存 NoSQL
【后端面经】【缓存】33|缓存模式:缓存模式能不能解决缓存一致性问题?-03 Refresh Ahead + SingleFlight + 删除缓存 + 延迟双删
【5月更文挑战第11天】Refresh Ahead模式通过CDC异步刷新缓存,但面临缓存一致性问题,可借鉴Write Back策略解决。SingleFlight限制并发加载,减少数据库压力,适合热点数据。删除缓存模式在更新数据库后删除缓存,一致性问题源于读写线程冲突。延迟双删模式两次删除,理论上减少不一致,但可能降低缓存命中率。选用模式需权衡优劣,延迟双删在低并发下较优。装饰器模式可用于实现多种缓存模式,无侵入地增强现有缓存系统。
501 2
|
存储 缓存 算法
同时使用线程本地变量以及对象缓存的问题
【7月更文挑战第15天】同时使用线程本地变量和对象缓存需小心处理以避免数据不一致、竞争条件及内存泄漏等问题。线程本地变量使各线程拥有独立存储,但若与对象缓存关联,可能导致多线程环境下访问旧数据。缺乏同步机制时,多线程并发修改缓存中的共享对象还会引起数据混乱。此外,若线程结束时未释放对象引用,可能导致内存泄漏。例如,在Web服务器场景下,若一更新缓存而另一线程仍获取旧数据,则可能返回错误信息;在图像处理应用中,若多线程无序修改算法对象则可能产生错误处理结果。因此,需确保数据一致性、避免竞争条件并妥善管理内存。
172 0