- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章android中图片的三级缓存cache策略(内存/文件/网络)由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
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 。
复制代码 代码如下
/* * 图片管理 * 异步获取图片,直接调用loadImage()函数,该函数自己判断是从缓存还是网络加载 * 同步获取图片,直接调用getBitmap()函数,该函数自己判断是从缓存还是网络加载 * 仅从本地获取图片,调用getBitmapFromNative() * 仅从网络加载图片,调用getBitmapFromHttp() * */ 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(bundle); 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(); } } /** * 依次从内存,缓存文件,网络上加载单个bitmap,不考虑线程的问题 */ 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; } /** * 从内存或者缓存文件中获取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; } /** * 下载链接的图片资源 * * @param url * * @return 图片 */ 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; } /** * 图片变为圆角 * @param bitmap:传入的bitmap * @param pixels:圆角的度数,值越大,圆角越大 * @return bitmap:加入圆角的bitmap */ 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中图片的三级缓存cache策略(内存/文件/网络)的文章就讲到这里了,如果你想了解更多关于android中图片的三级缓存cache策略(内存/文件/网络)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我需要将文本放在 中在一个 Div 中,在另一个 Div 中,在另一个 Div 中。所以这是它的样子: #document Change PIN
奇怪的事情发生了。 我有一个基本的 html 代码。 html,头部, body 。(因为我收到了一些反对票,这里是完整的代码) 这是我的CSS: html { backgroun
我正在尝试将 Assets 中的一组图像加载到 UICollectionview 中存在的 ImageView 中,但每当我运行应用程序时它都会显示错误。而且也没有显示图像。 我在ViewDidLoa
我需要根据带参数的 perl 脚本的输出更改一些环境变量。在 tcsh 中,我可以使用别名命令来评估 perl 脚本的输出。 tcsh: alias setsdk 'eval `/localhome/
我使用 Windows 身份验证创建了一个新的 Blazor(服务器端)应用程序,并使用 IIS Express 运行它。它将显示一条消息“Hello Domain\User!”来自右上方的以下 Ra
这是我的方法 void login(Event event);我想知道 Kotlin 中应该如何 最佳答案 在 Kotlin 中通配符运算符是 * 。它指示编译器它是未知的,但一旦知道,就不会有其他类
看下面的代码 for story in book if story.title.length < 140 - var story
我正在尝试用 C 语言学习字符串处理。我写了一个程序,它存储了一些音乐轨道,并帮助用户检查他/她想到的歌曲是否存在于存储的轨道中。这是通过要求用户输入一串字符来完成的。然后程序使用 strstr()
我正在学习 sscanf 并遇到如下格式字符串: sscanf("%[^:]:%[^*=]%*[*=]%n",a,b,&c); 我理解 %[^:] 部分意味着扫描直到遇到 ':' 并将其分配给 a。:
def char_check(x,y): if (str(x) in y or x.find(y) > -1) or (str(y) in x or y.find(x) > -1):
我有一种情况,我想将文本文件中的现有行包含到一个新 block 中。 line 1 line 2 line in block line 3 line 4 应该变成 line 1 line 2 line
我有一个新项目,我正在尝试设置 Django 调试工具栏。首先,我尝试了快速设置,它只涉及将 'debug_toolbar' 添加到我的已安装应用程序列表中。有了这个,当我转到我的根 URL 时,调试
在 Matlab 中,如果我有一个函数 f,例如签名是 f(a,b,c),我可以创建一个只有一个变量 b 的函数,它将使用固定的 a=a1 和 c=c1 调用 f: g = @(b) f(a1, b,
我不明白为什么 ForEach 中的元素之间有多余的垂直间距在 VStack 里面在 ScrollView 里面使用 GeometryReader 时渲染自定义水平分隔线。 Scrol
我想知道,是否有关于何时使用 session 和 cookie 的指南或最佳实践? 什么应该和什么不应该存储在其中?谢谢! 最佳答案 这些文档很好地了解了 session cookie 的安全问题以及
我在 scipy/numpy 中有一个 Nx3 矩阵,我想用它制作一个 3 维条形图,其中 X 轴和 Y 轴由矩阵的第一列和第二列的值、高度确定每个条形的 是矩阵中的第三列,条形的数量由 N 确定。
假设我用两种不同的方式初始化信号量 sem_init(&randomsem,0,1) sem_init(&randomsem,0,0) 现在, sem_wait(&randomsem) 在这两种情况下
我怀疑该值如何存储在“WORD”中,因为 PStr 包含实际输出。? 既然Pstr中存储的是小写到大写的字母,那么在printf中如何将其给出为“WORD”。有人可以吗?解释一下? #include
我有一个 3x3 数组: var my_array = [[0,1,2], [3,4,5], [6,7,8]]; 并想获得它的第一个 2
我意识到您可以使用如下方式轻松检查焦点: var hasFocus = true; $(window).blur(function(){ hasFocus = false; }); $(win
我是一名优秀的程序员,十分优秀!