iis服务器助手广告广告
返回顶部
首页 > 资讯 > 移动开发 >android中图片的三级缓存cache策略(内存/文件/网络)
  • 342
分享到

android中图片的三级缓存cache策略(内存/文件/网络)

图片cacheAndroid 2022-06-06 10:06:38 342人浏览 泡泡鱼
摘要

1.简介 现在Android应用中不可避免的要使用图片,有些图片是可以变化的,需要每次启动时从网络拉取,这种场景在有广告位的应用以及纯图片应用(比如百度美拍)中比较多。现在有一

1.简介
现在Android应用中不可避免的要使用图片,有些图片是可以变化的,需要每次启动时从网络拉取,这种场景在有广告位的应用以及纯图片应用(比如百度美拍)中比较多。
现在有一个问题:假如每次启动的时候都从网络拉取图片的话,势必会消耗很多流量。在当前的状况下,对于非wifi用户来说,流量还是很贵的,一个很耗流量的应用,其用户数量级肯定要受到影响。当然,我想,向百度美拍这样的应用,必然也有其内部的图片缓存策略。总之,图片缓存是很重要而且是必须的。
2.图片缓存的原理
实现图片缓存也不难,需要有相应的cache策略。这里我采用 内存-文件-网络 三层cache机制,其中内存缓存包括强引用缓存和软引用缓存(SoftReference),其实网络不算cache,这里姑且也把它划到缓存的层次结构中。当根据url向网络拉取图片的时候,先从内存中找,如果内存中没有,再从缓存文件中查找,如果缓存文件中也没有,再从网络上通过Http请求拉取图片。在键值对(key-value)中,这个图片缓存的key是图片url的hash值,value就是bitmap。所以,按照这个逻辑,只要一个url被下载过,其图片就被缓存起来了。
关于Java中对象的软引用(SoftReference),如果一个对象具有软引用,内存空间足够,垃 圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高 速缓存。使用软引用能防止内存泄露,增强程序的健壮性。
从代码上来说,采用一个ImageManager来负责图片的管理和缓存,函数接口为public void loadBitmap(String url, Handler handler) ;其中url为要下载的图片地址,handler为图片下载成功后的回调,在handler中处理message,而message中包含了图片的信息以及bitmap对象。ImageManager中使用的ImageMemoryCache(内存缓存)、ImageFileCache(文件缓存)以及LruCache(最近最久未使用缓存)会在后续文章中介绍。
3.代码ImageManager.java
代码如下:

public class ImageManager implements IManager
{
private final static String TAG = "ImageManager";
private ImageMemoryCache imageMemoryCache; //内存缓存
private ImageFileCache imageFileCache; //文件缓存
//正在下载的image列表
public static HashMap<String, Handler> onGoingTaskMap = new HashMap<String, Handler>();
//等待下载的image列表
public static HashMap<String, Handler> waitingTaskMap = new HashMap<String, Handler>();
//同时下载图片的线程个数
final static int MAX_DOWNLOAD_IMAGE_THREAD = 4;
private final Handler downloadStatusHandler = new Handler(){
public void handleMessage(Message msg)
{
startDownloadNext();
}
};
public ImageManager()
{
imageMemoryCache = new ImageMemoryCache();
imageFileCache = new ImageFileCache();
}

public void loadBitmap(String url, Handler handler)
{
//先从内存缓存中获取,取到直接加载
Bitmap bitmap = getBitmapFromNative(url);
if (bitmap != null)
{
Logger.d(TAG, "loadBitmap:loaded from native");
Message msg = Message.obtain();
Bundle bundle = new Bundle();
bundle.putString("url", url);
msg.obj = bitmap;
msg.setData(bu ndle);
handler.sendMessage(msg);
}
else
{
Logger.d(TAG, "loadBitmap:will load by network");
downloadBmpOnNewThread(url, handler);
}
}

private void downloadBmpOnNewThread(final String url, final Handler handler)
{
Logger.d(TAG, "ongoingTaskMap'size=" + ongoingTaskMap.size());
if (ongoingTaskMap.size() >= MAX_DOWNLOAD_IMAGE_THREAD)
{
synchronized (waitingTaskMap)
{
waitingTaskMap.put(url, handler);
}
}
else
{
synchronized (ongoingTaskMap)
{
ongoingTaskMap.put(url, handler);
}
new Thread()
{
public void run()
{
Bitmap bmp = getBitmapFromHttp(url);
// 不论下载是否成功,都从下载队列中移除,再由业务逻辑判断是否重新下载
// 下载图片使用了httpClientRequest,本身已经带了重连机制
synchronized (ongoingTaskMap)
{
ongoingTaskMap.remove(url);
}
if(downloadStatusHandler != null)
{
downloadStatusHandler.sendEmptyMessage(0);
}
Message msg = Message.obtain();
msg.obj = bmp;
Bundle bundle = new Bundle();
bundle.putString("url", url);
msg.setData(bundle);
if(handler != null)
{
handler.sendMessage(msg);
}
}
}.start();
}
}

public Bitmap getBitmap(String url)
{
// 从内存缓存中获取图片
Bitmap bitmap = imageMemoryCache.getBitmapFromMemory(url);
if (bitmap == null)
{
// 文件缓存中获取
bitmap = imageFileCache.getImageFromFile(url);
if (bitmap != null)
{
// 添加到内存缓存
imageMemoryCache.addBitmapToMemory(url, bitmap);
}
else
{
// 从网络获取
bitmap = getBitmapFromHttp(url);
}
}
return bitmap;
}

public Bitmap getBitmapFromNative(String url)
{
Bitmap bitmap = null;
bitmap = imageMemoryCache.getBitmapFromMemory(url);
if(bitmap == null)
{
bitmap = imageFileCache.getImageFromFile(url);
if(bitmap != null)
{
// 添加到内存缓存
imageMemoryCache.addBitmapToMemory(url, bitmap);
}
}
return bitmap;
}

public Bitmap getBitmapFromHttp(String url)
{
Bitmap bmp = null;
try
{
byte[] tmpPicByte = getImageBytes(url);
if (tmpPicByte != null)
{
bmp = BitmapFactory.decodeByteArray(tmpPicByte, 0,
tmpPicByte.length);
}
tmpPicByte = null;
}
catch(Exception e)
{
e.printStackTrace();
}
if(bmp != null)
{
// 添加到文件缓存
imageFileCache.saveBitmapToFile(bmp, url);
// 添加到内存缓存
imageMemoryCache.addBitmapToMemory(url, bmp);
}
return bmp;
}

public byte[] getImageBytes(String url)
{
byte[] pic = null;
if (url != null && !"".equals(url))
{
Requester request = RequesterFactory.getRequester(
Requester.REQUEST_REMOTE, RequesterFactory.IMPL_HC);
// 执行请求
MyResponse myResponse = null;
MyRequest mMyRequest;
mMyRequest = new MyRequest();
mMyRequest.setUrl(url);
mMyRequest.addHeader(HttpHeader.REQ.ACCEPT_ENcoding, "identity");
InputStream is = null;
ByteArrayOutputStream baos = null;
try {
myResponse = request.execute(mMyRequest);
is = myResponse.getInputStream().getImpl();
baos = new ByteArrayOutputStream();
byte[] b = new byte[512];
int len = 0;
while ((len = is.read(b)) != -1)
{
baos.write(b, 0, len);
baos.flush();
}
pic = baos.toByteArray();
Logger.d(TAG, "icon bytes.length=" + pic.length);
}
catch (Exception e3)
{
e3.printStackTrace();
try
{
Logger.e(TAG,
"download shortcut icon faild and responsecode="
+ myResponse.getStatusCode());
}
catch (Exception e4)
{
e4.printStackTrace();
}
}
finally
{
try
{
if (is != null)
{
is.close();
is = null;
}
}
catch (Exception e2)
{
e2.printStackTrace();
}
try
{
if (baos != null)
{
baos.close();
baos = null;
}
}
catch (Exception e2)
{
e2.printStackTrace();
}
try
{
request.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
}
return pic;
}

private void startDownloadNext()
{
synchronized(waitingTaskMap)
{
Logger.d(TAG, "begin start next");
Iterator iter = waitingTaskMap.entrySet().iterator();
while (iter.hasNext())
{
Map.Entry entry = (Map.Entry) iter.next();
Logger.d(TAG, "WaitingTaskMap isn't null,url=" + (String)entry.geTKEy());
if(entry != null)
{
waitingTaskMap.remove(entry.getKey());
downloadBmpOnNewThread((String)entry.getKey(), (Handler)entry.getValue());
}
break;
}
}
}
public String startDownloadNext_ForUnitTest()
{
String urlString = null;
synchronized(waitingTaskMap)
{
Logger.d(TAG, "begin start next");
Iterator iter = waitingTaskMap.entrySet().iterator();
while (iter.hasNext())
{
Map.Entry entry = (Map.Entry) iter.next();
urlString = (String)entry.getKey();
waitingTaskMap.remove(entry.getKey());
break;
}
}
return urlString;
}

public static Bitmap toRoundCorner(Bitmap bitmap, int pixels)
{
if(bitmap == null)
return null;
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);
canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
final RectF rectF = new RectF(rect);
final float roundPx = pixels;
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
public byte managerId()
{
return IMAGE_ID;
}
}
您可能感兴趣的文章:Android图片三级缓存开发浅谈Android 中图片的三级缓存策略Android图片三级缓存的原理及其实现Android中Rxjava实现三级缓存的两种方式详解Android 图片的三级缓存及图片压缩Android中图片的三级缓存机制Android图片三级缓存策略(网络、本地、内存缓存)Android使用缓存机制实现文件下载及异步请求图片加三级缓存Android实现图片异步请求加三级缓存Android三级缓存原理讲解


--结束END--

本文标题: android中图片的三级缓存cache策略(内存/文件/网络)

本文链接: https://www.lsjlt.com/news/27541.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 浅谈Android 中图片的三级缓存策略
    什么是三级缓存? 内存缓存,优先加载,速度最快 本地缓存,次优先加载,速度快 网络缓存,最后加载,速度慢,浪费流量为什么要进行三级缓存三级缓存策略,最实在的意义就是 减少不必要的流量消耗,增加加载速度 。如今的 APP 网络交互似乎已...
    99+
    2023-05-30
    android 图片 三级缓存
  • 详解Android中图片的三级缓存及实例
    详解Android中图片的三级缓存及实例为什么要使用三级缓存 如今的 Android App 经常会需要网络交互,通过网络获取图片是再正常不过的事了 假如每次启动的时候都从网络拉取图片的话,势必会消耗很多流量。在当前的状况下,对于非wi...
    99+
    2023-05-30
    android 三级缓存 roi
  • Android 图片的三级缓存机制实例分析
    Android 图片的三级缓存机制实例分析当我们获取图片的时候,如果不加以协调好图片的缓存,就会造成大流量,费流量应用,用户体验不好,影响后期发展。为此,我特地分享Android图片的三级缓存机制之从网络中获取图片,来优化应用,具体分三步进...
    99+
    2023-05-31
    android 图片 三级缓存
  • Android图片三级缓存的原理及其实现
    为什么要使用三级缓存 如今的 Android App 经常会需要网络交互,通过网络获取图片是再正常不过的事了 假如每次启动的时候都从网络拉取图片的话,势必会消耗很多流量。在当前的状况下,对于非wifi用户来说,流量还是很贵的,一个很耗流...
    99+
    2023-05-30
    android 图片 三级缓存
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作