1.三级缓存设计步骤:
* 从内存中取图片
* 从本地文件中取图片
向内存中保持一份
* 请求网络图片,获取图片,显示到控件上
向内存存一份
向本地文件中存一份
1 package com.atguigu.beijingnews.utils; 2 3 import android.graphics.Bitmap; 4 import android.os.Handler; 5 6 public class BitmapCacheUtils { 7 8 /** 9 * 网络缓存工具类 10 */ 11 private NetCacheUtils netCacheUtils; 12 13 /** 14 * 本地缓存工具类 15 */ 16 17 private LocalCacheUtils localCacheUtils; 18 19 /** 20 内存缓存工具类 21 */ 22 private MemoryCacheUtils memoryCacheUtils; 23 24 public BitmapCacheUtils(Handler handler) { 25 memoryCacheUtils = new MemoryCacheUtils(); 26 localCacheUtils = new LocalCacheUtils(memoryCacheUtils); 27 netCacheUtils = new NetCacheUtils(handler,localCacheUtils,memoryCacheUtils); 28 29 } 30 31 32 /** 33 * 三级缓存设计步骤: 34 * * 从内存中取图片 35 * * 从本地文件中取图片 36 * 向内存中保持一份 37 * * 请求网络图片,获取图片,显示到控件上,Hanlder,postion 38 * * 向内存存一份 39 * * 向本地文件中存一份 40 * 41 * @param imageUrl 42 * @param position 43 * @return 44 */ 45 public Bitmap getBitmap(String imageUrl, int position) { 46 //1.从内存中取图片 47 if (memoryCacheUtils != null) { 48 Bitmap bitmap = memoryCacheUtils.getBitmapFromUrl(imageUrl); 49 if (bitmap != null) { 50 LogUtil.e("内存加载图片成功=="+position); 51 return bitmap; 52 } 53 } 54 55 //2.从本地文件中取图片 56 if (localCacheUtils != null) { 57 Bitmap bitmap = localCacheUtils.getBitmapFromUrl(imageUrl); 58 if (bitmap != null) { 59 LogUtil.e("本地加载图片成功=="+position); 60 return bitmap; 61 } 62 } 63 64 //3.请求网络图片 65 netCacheUtils.getBitmapFomNet(imageUrl, position); 66 return null; 67 } 68 }
2.网络缓存
线程池类Executors的使用
public static ExecutorService newCachedThreadPool()
创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。对于执行很多短期异步任务的程序而言,这些线程池通常可提高程序性能。调用 execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。因此,长时间保持空闲的线程池不会使用任何资源。注意,可以使用 ThreadPoolExecutor 构造方法创建具有类似属性但细节不同(例如超时参数)的线程池。
public static ExecutorService newFixedThreadPool(int nThreads)
创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。在任意点,在大多数 nThreads 线程会处于处理任务的活动状态。如果在所有线程处于活动状态时提交附加任务,则在有可用线程之前,附加任务将在队列中等待。如果在关闭前的执行期间由于失败而导致任何线程终止,那么一个新线程将代替它执行后续的任务(如果需要)。在某个线程被显式地关闭之前,池中的线程将一直存在。
1 package com.atguigu.beijingnews.utils; 2 3 import android.graphics.Bitmap; 4 import android.graphics.BitmapFactory; 5 import android.os.Handler; 6 import android.os.Message; 7 8 import java.io.IOException; 9 import java.io.InputStream; 10 import java.net.HttpURLConnection; 11 import java.net.URL; 12 import java.util.concurrent.ExecutorService; 13 import java.util.concurrent.Executors; 14 15 public class NetCacheUtils { 16 17 /** 18 * 请求图片成功 19 */ 20 public static final int SUCESS = 1; 21 /** 22 * 请求图片失败 23 */ 24 public static final int FAIL = 2; 25 private final Handler handler; 26 /** 27 * 本地缓存工具类 28 */ 29 private final LocalCacheUtils localCacheUtils; 30 /** 31 * 内存缓存工具类 32 */ 33 private final MemoryCacheUtils memoryCacheUtils; 34 /** 35 * 线程池类 36 */ 37 private ExecutorService service; 38 39 public NetCacheUtils(Handler handler, LocalCacheUtils localCacheUtils, MemoryCacheUtils memoryCacheUtils) { 40 this.handler = handler; 41 service = Executors.newFixedThreadPool(10); 42 this.localCacheUtils = localCacheUtils; 43 this.memoryCacheUtils =memoryCacheUtils; 44 } 45 46 //联网请求得到图片 47 public void getBitmapFomNet(String imageUrl, int position) { 48 // new Thread(new MyRunnable(imageUrl,position)).start(); 49 service.execute(new MyRunnable(imageUrl,position)); 50 } 51 52 class MyRunnable implements Runnable{ 53 54 private final String imageUrl; 55 private final int position; 56 57 public MyRunnable(String imageUrl, int position) { 58 this.imageUrl = imageUrl; 59 this.position = position; 60 } 61 62 @Override 63 public void run() { 64 //子线程 65 //请求网络图片 66 try { 67 URL urL = new URL(imageUrl); 68 HttpURLConnection connection = (HttpURLConnection) urL.openConnection(); 69 connection.setRequestMethod("GET");//只能大写 70 connection.setConnectTimeout(4000); 71 connection.setReadTimeout(4000); 72 connection.connect();//可写可不写 73 int code = connection.getResponseCode(); 74 if(code ==200){ 75 InputStream is = connection.getInputStream(); 76 Bitmap bitmap = BitmapFactory.decodeStream(is); 77 78 //显示到控件上,发消息吧Bitmap发出去和position 79 Message msg = Message.obtain(); 80 msg.what = SUCESS; 81 msg.arg1 = position; 82 msg.obj = bitmap; 83 handler.sendMessage(msg); 84 85 //在内存中缓存一份 86 memoryCacheUtils.putBitmap(imageUrl,bitmap); 87 //在本地中缓存一份 88 localCacheUtils.putBitmap(imageUrl,bitmap); 89 } 90 } catch (IOException e) { 91 e.printStackTrace(); 92 Message msg = Message.obtain(); 93 msg.what = FAIL; 94 msg.arg1 = position; 95 handler.sendMessage(msg); 96 } 97 } 98 } 99 }
3.本地缓存
File file = new File(CACHE_DIR, fileName); FileInputStream FileOutputStream 文件读写方式
演示把图片移除后,在查看
C:UsersAdministrator>adb shell
# cd /mnt/sdcard/atguigu_beijingnews
cd /mnt/sdcard/atguigu_beijingnews
# rm *
rm *
1 package com.atguigu.beijingnews.utils; 2 3 import android.graphics.Bitmap; 4 import android.graphics.BitmapFactory; 5 import android.os.Environment; 6 7 import java.io.File; 8 import java.io.FileInputStream; 9 import java.io.FileOutputStream; 10 11 public class LocalCacheUtils { 12 private final MemoryCacheUtils memoryCacheUtils; 13 14 public LocalCacheUtils(MemoryCacheUtils memoryCacheUtils) { 15 this.memoryCacheUtils = memoryCacheUtils; 16 } 17 18 /** 19 * 根据Url获取图片 20 * @param imageUrl 21 * @return 22 */ 23 public Bitmap getBitmapFromUrl(String imageUrl) { 24 //判断sdcard是否挂载 25 if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ 26 //保存图片在/mnt/sdcard/beijingnews/http://192.168.21.165:8080/xsxxxx.png 27 //保存图片在/mnt/sdcard/beijingnews/llkskljskljklsjklsllsl 28 try { 29 String fileName = MD5Encoder.encode(imageUrl);//llkskljskljklsjklsllsl 30 31 ///mnt/sdcard/beijingnews/llkskljskljklsjklsllsl 32 File file = new File(Environment.getExternalStorageDirectory()+"/beijingnews",fileName); 33 34 35 36 37 if(file.exists()){ 38 39 FileInputStream is = new FileInputStream(file); 40 Bitmap bitmap = BitmapFactory.decodeStream(is); 41 if(bitmap != null){ 42 memoryCacheUtils.putBitmap(imageUrl,bitmap); 43 LogUtil.e("把从本地保持到内存中"); 44 } 45 return bitmap; 46 47 } 48 49 } catch (Exception e) { 50 e.printStackTrace(); 51 LogUtil.e("图片获取失败"); 52 } 53 } 54 55 return null; 56 } 57 58 /** 59 * 根据Url保存图片 60 * @param imageUrl url 61 * @param bitmap 图片 62 */ 63 public void putBitmap(String imageUrl, Bitmap bitmap) { 64 65 //判断sdcard是否挂载 66 if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ 67 //保存图片在/mnt/sdcard/beijingnews/http://192.168.21.165:8080/xsxxxx.png 68 //保存图片在/mnt/sdcard/beijingnews/llkskljskljklsjklsllsl 69 try { 70 String fileName = MD5Encoder.encode(imageUrl);//llkskljskljklsjklsllsl 71 72 ///mnt/sdcard/beijingnews/llkskljskljklsjklsllsl 73 File file = new File(Environment.getExternalStorageDirectory()+"/beijingnews",fileName); 74 75 File parentFile = file.getParentFile();//mnt/sdcard/beijingnews 76 if(!parentFile.exists()){ 77 //创建目录 78 parentFile.mkdirs(); 79 } 80 81 82 if(!file.exists()){ 83 file.createNewFile(); 84 } 85 //保存图片 86 bitmap.compress(Bitmap.CompressFormat.PNG,100,new FileOutputStream(file)); 87 88 } catch (Exception e) { 89 e.printStackTrace(); 90 LogUtil.e("图片本地缓存失败"); 91 } 92 } 93 94 95 } 96 }
4.内存缓存
引用级别
我们经常会使用一种非常流行的内存缓存技术的实现,即软引用或弱引用 (SoftReference or WeakReference)。
但是现在已经不再推荐使用这种方式了,因为从 Android 2.3 (API Level 9)开始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象;
另外,Android 3.0 (API Level 11)中,图片的数据会存储在本地的内存当中,因而无法用一种可预见的方式将其释放,
这就有潜在的风险造成应用程序的内存溢出并崩溃。所以看到还有很多相关文章还在推荐用软引用或弱引用 (SoftReference or WeakReference),就有点out了
Android3.0后提出新的方式
LruCache 缓存的集合,把常用的数据,保留起来,把不常用的给回收。
Lru近期最少使用算法
1 package com.atguigu.beijingnews.utils; 2 3 import android.graphics.Bitmap; 4 5 import org.xutils.cache.LruCache; 6 7 /** 8 * 作用:Java之软引用&弱引用&虚引用 9 */ 10 public class MemoryCacheUtils { 11 12 /** 13 * 集合 14 */ 15 private LruCache<String,Bitmap> lruCache; 16 17 public MemoryCacheUtils(){ 18 //使用了系统分配给应用程序的八分之一内存来作为缓存大小 19 int maxSize = (int) (Runtime.getRuntime().maxMemory()/1024/8); 20 lruCache = new LruCache<String,Bitmap>(maxSize){ 21 @Override 22 protected int sizeOf(String key, Bitmap value) { 23 // return super.sizeOf(key, value); 24 return (value.getRowBytes() * value.getHeight())/1024; 25 } 26 }; 27 } 28 29 /** 30 * 根据url从内存中获取图片 31 * @param imageUrl 32 * @return 33 */ 34 public Bitmap getBitmapFromUrl(String imageUrl) { 35 return lruCache.get(imageUrl); 36 } 37 38 /** 39 * 根据url保存图片到lruCache集合中 40 * @param imageUrl 图片路径 41 * @param bitmap 图片 42 */ 43 public void putBitmap(String imageUrl, Bitmap bitmap) { 44 lruCache.put(imageUrl,bitmap); 45 } 46 }