Android使用 LruCache 缓存图片

合集下载

移动应用开发中常见的缓存优化技巧

移动应用开发中常见的缓存优化技巧

移动应用开发中常见的缓存优化技巧在移动应用开发过程中,缓存的使用是提高应用性能和用户体验的关键之一。

合理地使用缓存可以减少网络请求,提高数据加载速度,减轻服务器负载,降低用户流量消耗,以及提升应用的整体响应速度。

本文将介绍一些常见的缓存优化技巧,帮助开发者更好地降低应用的数据耗费和提升应用性能。

1. 内存缓存内存缓存是最快速、最便捷的缓存方式之一。

通过将数据保存到内存中,可以快速地读取数据,避免频繁的网络请求。

Android平台提供了LruCache类,可以在应用程序的内存中实现对象缓存,有效地管理内存资源。

在实际开发中,我们可以将一些频繁使用的数据,如图片、文本等缓存在内存中,提高数据的读取速度。

2. 硬盘缓存和内存缓存相比,硬盘缓存的读写速度较慢,但却可以持久保存数据。

硬盘缓存适用于一些需要较长时间保存的数据,如应用的设置、用户的登录信息等。

Android平台提供了DiskLruCache类,可以将数据缓存到文件系统中,实现数据的长期存储,并提供了数据过期策略,以避免数据的无效使用。

3. 离线缓存离线缓存是一种在网络不稳定或者无网络环境下,提供数据的缓存技术。

通过离线缓存,即使用户处于无网络状态,依然可以正常获取数据。

在设计离线缓存时,可以使用localStorage或IndexedDB等本地存储技术,将数据缓存到本地设备中,并在无网络状态下优先读取本地缓存的数据。

4. 数据预加载数据预加载技术可以在应用启动时,提前加载一些可能会用到的数据。

通过在后台进行数据的预加载,可以提高用户初始页面的加载速度,避免用户长时间等待。

在应用开发中,可以通过不可见的Activity或者Service来进行数据的预加载,提前获取服务器数据,并缓存在设备中,以提高用户体验。

5. 图片缓存图片的加载是移动应用中常见的性能瓶颈之一,过多的网络请求会拖慢应用的速度。

针对这个问题,开发者可以采取图像压缩、延迟加载、图片缓存等策略来优化应用。

Android 平滑图片加载和缓存库 Glide 使用详解

Android 平滑图片加载和缓存库 Glide 使用详解

Android 平滑图片加载和缓存库Glide 使用详解
来源:互联网时间:2015-8-26 8:04:09
本篇文章主要介绍了"Android 平滑图片加载和缓存库Glide 使用详解",主要涉
及到方面的内容,对于Android开发感兴趣的同学可以参考一下:在图片加载库烂大街的今天,选择一个适合自己使用的图片加载库已经成为了每一个Android开发者的必经之路。

现在市面上知名的图片加载库有UIL,Picasso,V...


在图片加载库烂大街的今天,选择一个适合自己使用的图片加载库已经成为了每一个Android开发者的必经之路。

现在市面上知名的图片加载库有UIL,Picass o,Volley ImageLoader,Fresco以及我们今天的主角Glide。

它们各有千秋,不能评定谁一定比谁好,只能说哪一个更适合你。

我的理解
下面我来谈一下个人对这些图片加载库的理解,如有错误,还望指教。

Universal Image Loader:一个强大的图片加载库,包含各种各样的配置,最老牌,使用也最广泛。

Picasso: Square出品,必属精品。

和OkHttp搭配起来更配呦!
Volley ImageLoader:Google官方出品,可惜不能加载本地图片~ Fresco:Facebook出的,天生骄傲!不是一般的强大。

Glide:Google推荐的图片加载库,专注于流畅的滚动。

更多详情请看stackoverflow上这个问题。

教你写Android-ImageLoader框架之图片缓存-(完结篇)

教你写Android-ImageLoader框架之图片缓存-(完结篇)

教你写Android ImageLoader框架之图片缓存(完结篇)在教你写Android ImageLoader框架系列博文中,我们从基本架构到具体实现已经更新了大部分的内容。

今天,我们来讲最后一个关键点,即图片的缓存。

为了用户体验,通常情况下我们都会将已经下载的图片缓存起来,一般来说内存和本地都会有图片缓存。

那既然是框架,必然需要有很好的定制性,这让我们又自然而然的想到了抽象。

下面我们就一起来看看缓存的实现吧。

缓存接口在教你写Android ImageLoader框架之图片加载与加载策略我们聊到了Loader,然后阐述了AbsLoader的基本逻辑,其中就有图片缓存。

因此AbsLoader中必然含有缓存对象的引用。

我们看看相关代码:/*** @author mrsimple*/public abstract class AbsLoader implements Loader {/*** 图片缓存*/private static BitmapCache mCache = SimpleImageLoader.getInstance().getConfig().bitmapCache;// 代码省略}23456789101112 AbsLoader中定义了一个static的BitmapCache对象,这个就是图片缓存对象。

那为什么是static呢?因为不管Loader有多少个,缓存对象都应该是共享的,也就是缓存只有一份。

说了那么多,那我们先来了解一下BitmapCache吧。

public interface BitmapCache {public Bitmap get(BitmapRequest key);public void put(BitmapRequest key, Bitmap value);public void remove(BitmapRequest key);}12345679 BitmapCache很简单,只声明了获取、添加、移除三个方法来操作图片缓存。

简单的图片缓存

简单的图片缓存

简单的图片缓存_V客学院Android技术分享(V客学院android开发小知识)在开发Android项目中,大多数人会接触到异步加载图片或者是加载大量图片等,这其中会牵扯到一个很重要的问题:用户的流量。

假设打开一款APP,而这款APP没有经过图片缓存,那么每次打开APP就会请求一次网络获取图片(注:当然还有其他数据,这里只处理图片),结果一是浪费用户大量的流量,二是在没有网络情况下有图片的布局显示不出图片。

现在一九八网络科技V客学院的android开发大神就介绍了一种简易的图片缓存牵扯到了软引用和本地文件缓存。

何为软引用?从JDK1.2开始,java将对象分成了四种级别,以达到程序对对象生财周期的灵活控制,这四个级别由强到弱是:强引用,软引用,弱引用,虚引用。

强引用就不多说了,就是我们平时直接new出来的一个对象,不做任何的修饰,就是强引用。

虚引用暂未使用过也就没做过深入了解,弱引用的使用方式基本和软引用是一样的,所以就重点看了一下应用程序如何使用软引用。

如果一个对象只具有软引用,那么如果内存如果够用的话,GC 就不会回收它,如果内存不足了,就会优先回收只有软引用的对象内存,而保证不会内存溢出。

基于软引用的这个特性,我们可以使用软引用来实现内存敏感区的高速缓存,因此为了防止内存溢出的发生,在处理一些占用内存较大且声明周期较长的对象的时候,我们可以尽量使用软引用,例如: Context及其子类对象,Drawable及其子类对象,Bitmap位图对象等,在创建这些类的对象的时候,尽量将其声明为软引用。

(以上解析网上转载)。

软引用调用对象声明:SoftReference instance。

本地文件缓存指的是第一次进入APP时将从网上获取下来的图片存在本地,等多次进入APP时先在本地文件缓存文件中判断是否存在,存在即加载本地图片。

以下是本篇代码详细解释。

单独将网络请求主体代码列出来做一个网络请求工具类,作用是代码的优化,多次请求网络时,都需要声明一次网络请求方法,既然如此我们单独列出来做成一个公共调用的工具类。

详解Android图片的三级缓存及图片压缩

详解Android图片的三级缓存及图片压缩

详解Android图⽚的三级缓存及图⽚压缩为什么需要图⽚缓存Android默认给每个应⽤只分配16M的内存,所以如果加载过多的图⽚,为了防⽌内存溢出,应该将图⽚缓存起来。

图⽚的三级缓存分别是:内存缓存本地缓存⽹络缓存其中,内存缓存应优先加载,它速度最快;本地缓存次优先加载,它速度也快;⽹络缓存不应该优先加载,它⾛⽹络,速度慢且耗流量。

三级缓存的具体实现⽹络缓存根据图⽚的url去加载图⽚在本地和内存中缓存public class NetCacheUtils {private LocalCacheUtils mLocalCacheUtils;private MemoryCacheUtils mMemoryCacheUtils;public NetCacheUtils(LocalCacheUtils localCacheUtils,MemoryCacheUtils memoryCacheUtils) {mLocalCacheUtils = localCacheUtils;mMemoryCacheUtils = memoryCacheUtils;}/*** 从⽹络下载图⽚** @param ivPic* @param url*/public void getBitmapFromNet(ImageView ivPic, String url) {new BitmapTask().execute(ivPic, url);// 启动AsyncTask,// 参数会在doInbackground中获取}/*** Handler和线程池的封装** 第⼀个泛型: 参数类型第⼆个泛型: 更新进度的泛型, 第三个泛型是onPostExecute的返回结果***/class BitmapTask extends AsyncTask<Object, Void, Bitmap> {private ImageView ivPic;private String url;/*** 后台耗时⽅法在此执⾏, ⼦线程*/@Overrideprotected Bitmap doInBackground(Object... params) {ivPic = (ImageView) params[0];url = (String) params[1];ivPic.setTag(url);// 将url和imageview绑定return downloadBitmap(url);}/*** 更新进度, 主线程@Overrideprotected void onProgressUpdate(Void... values) {super.onProgressUpdate(values);}/*** 耗时⽅法结束后,执⾏该⽅法, 主线程*/@Overrideprotected void onPostExecute(Bitmap result) {if (result != null) {String bindUrl = (String) ivPic.getTag();if (url.equals(bindUrl)) {// 确保图⽚设定给了正确的imageviewivPic.setImageBitmap(result);mLocalCacheUtils.setBitmapToLocal(url, result);// 将图⽚保存在本地mMemoryCacheUtils.setBitmapToMemory(url, result);// 将图⽚保存在内存System.out.println("从⽹络缓存读取图⽚啦...");}}}}/*** 下载图⽚** @param url* @return*/private Bitmap downloadBitmap(String url) {HttpURLConnection conn = null;try {conn = (HttpURLConnection) new URL(url).openConnection();conn.setConnectTimeout(5000);conn.setReadTimeout(5000);conn.setRequestMethod("GET");conn.connect();int responseCode = conn.getResponseCode();if (responseCode == 200) {InputStream inputStream = conn.getInputStream();//图⽚压缩处理BitmapFactory.Options option = new BitmapFactory.Options();option.inSampleSize = 2;//宽⾼都压缩为原来的⼆分之⼀, 此参数需要根据图⽚要展⽰的⼤⼩来确定 option.inPreferredConfig = Bitmap.Config.RGB_565;//设置图⽚格式Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, option);return bitmap;}} catch (Exception e) {e.printStackTrace();} finally {conn.disconnect();}return null;}}本地缓存两个⽅法:设置本地缓存,获取本地缓存public class LocalCacheUtils {public static final String CACHE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/local_cache";/*** 从本地sdcard读图⽚public Bitmap getBitmapFromLocal(String url) {try {String fileName = MD5Encoder.encode(url);File file = new File(CACHE_PATH, fileName);if (file.exists()) {Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(file));return bitmap;}} catch (Exception e) {e.printStackTrace();}return null;}/*** 向sdcard写图⽚** @param url* @param bitmap*/public void setBitmapToLocal(String url, Bitmap bitmap) {try {String fileName = MD5Encoder.encode(url);File file = new File(CACHE_PATH, fileName);File parentFile = file.getParentFile();if (!parentFile.exists()) {// 如果⽂件夹不存在, 创建⽂件夹parentFile.mkdirs();}// 将图⽚保存在本地press(CompressFormat.JPEG, 100,new FileOutputStream(file));} catch (Exception e) {e.printStackTrace();}}}内存缓存两个⽅法:设置内存缓存,获取内存缓存问题:如果使⽤HashMap存储图⽚时,当图⽚越来越多时,会导致内存溢出,因为它是强引⽤,java的垃圾回收器不会回收。

Android图片缓存之Lru算法

Android图片缓存之Lru算法

Android图⽚缓存之Lru算法前⾔:上篇我们总结了Bitmap的处理,同时对⽐了各种处理的效率以及对内存占⽤⼤⼩。

我们得知⼀个应⽤如果使⽤⼤量图⽚就会导致OOM(out of memory),那该如何处理才能近可能的降低oom发⽣的概率呢?之前我们⼀直在使⽤SoftReference软引⽤,SoftReference是⼀种现在已经不再推荐使⽤的⽅式,因为从 Android 2.3 (API Level 9)开始,垃圾回收器会更倾向于回收持有软引⽤或弱引⽤的对象,这让软引⽤变得不再可靠,所以今天我们来认识⼀种新的缓存处理算法Lru,然后学习⼀下基于Lru的Lrucache、DiskLruCache 实现我们的图⽚缓存。

图⽚缓存相关博客地址:Lru:LRU是Least Recently Used 的缩写,翻译过来就是“最近最少使⽤”,LRU缓存就是使⽤这种原理实现,简单的说就是缓存⼀定量的数据,当超过设定的阈值时就把⼀些过期的数据删除掉,⽐如我们缓存10000条数据,当数据⼩于10000时可以随意添加,当超过10000时就需要把新的数据添加进来,同时要把过期数据删除,以确保我们最⼤缓存10000条,那怎么确定删除哪条过期数据呢,采⽤LRU算法实现的话就是将最⽼的数据删掉。

基于LruCache实现内存缓存:1.)初始化MemoryCache这⾥内存缓存的是Drawable ⽽不是Bitmap 理由是Drawable相对Bitmap来说有很⼤的内存优势int maxMemory = (int) Runtime.getRuntime().maxMemory();//获取系统分配给应⽤的总内存⼤⼩int mCacheSize = maxMemory / 8;//设置图⽚内存缓存占⽤⼋分之⼀mMemoryCache = new LruCache<String, Drawable>(mCacheSize) {//必须重写此⽅法,来测量Bitmap的⼤⼩@Overrideprotected int sizeOf(String key, Drawable value) {if (value instanceof BitmapDrawable) {Bitmap bitmap = ((BitmapDrawable) value).getBitmap();return bitmap == null ? 0 : bitmap.getByteCount();}return super.sizeOf(key, value);}};2.)添加⼀个Drawable到内存缓存/*** 添加Drawable到内存缓存** @param key* @param drawable*/private void addDrawableToMemoryCache(String key, Drawable drawable) {if (getDrawableFromMemCache(key) == null && drawable != null) {mMemoryCache.put(key, drawable);}}3.)从内存缓存中获取⼀个Drawable/*** 从内存缓存中获取⼀个Drawable** @param key* @return*/public Drawable getDrawableFromMemCache(String key) {return mMemoryCache.get(key);}4.)从内存缓存中移除⼀个Drawable/**** @param key*/public void removeCacheFromMemory(String key) {mMemoryCache.remove(key);}5.)清空内存缓存/*** 清理内存缓存*/public void cleanMemoryCCache() {mMemoryCache.evictAll();}其实Lru缓存机制本质上就是存储在⼀个LinkedHashMap存储,为了保障插⼊的数据顺序,⽅便清理。

Android 图片加载性能优化总结

Android 图片加载性能优化总结

Android 图片加载性能优化总结一、Android Bitmap加载大尺寸图片优化:压缩原因:1.imageview大小如果是200*300那么加载个2000*3000的图片到内存中显然是浪费可耻滴行为;2.最重要的是图片过大时直接加载原图会造成OOM异常(out of memory内存溢出)所以一般对于大图我们需要进行下压缩处理看不懂英文的话木有关系,本篇会有介绍主要处理思路是:1.获取图片的像素宽高(不加载图片至内存中,所以不会占用资源)2.计算需要压缩的比例3.按将图片用计算出的比例压缩,并加载至内存中使用官网大图片加载教程(上面网址里的)对应代码就是:/*** 获取压缩后的图片* @param res* @param resId* @param reqWidth 所需图片压缩尺寸最小宽度* @param reqHeight 所需图片压缩尺寸最小高度* @return*/public static Bitmap decodeSampledBitmapFromResource(Resourcesres, int resId, int reqWidth, int reqHeight) {// 首先不加载图片,仅获取图片尺寸final BitmapFactory.Options options= new BitmapFactory.Options();// 当inJustDecodeBounds设为true时,不会加载图片仅获取图片尺寸信息options.inJustDecodeBounds = true;// 此时仅会将图片信息会保存至options对象内,decode方法不会返回bitmap 对象BitmapFactory.decodeResource(res, resId, options);// 计算压缩比例,如inSampleSize=4时,图片会压缩成原图的1/4options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);// 当inJustDecodeBounds设为false时,BitmapFactory.decode...就会返回图片对象了options.inJustDecodeBounds = false;// 利用计算的比例值获取压缩后的图片对象return BitmapFactory.decodeResource(res, resId, options);}代码详解:核心方法是BitmapFactory.decode...(...., options)...的意思是此外还有一系列的decodeFile/decodeStream等等方法,都是利用options灵活解析获取图片,只不过解析图片的来源不同罢了,比如网络图片获取,一般就是解析字节流信息然后decode获取图片实例Options是图片配置信息,参数详细介绍下:inJustDecodeBounds 是否只解析边界设为true时去decode获取图片,只会加载像素宽高信息设为false时decode则会完全加载图片inSampleSize 压缩比例比如原图200*300,如果值是2时会压缩成100*150; 是4则图片压缩成50*75最好是2的幂数,比如2 4 8 16 .....outHeight 图片原高度outWidth 图片原宽度其他参数自行研究,这里暂时只用到这几个decodeSampledBitmapFromResource方法内的三段代码对应上面的三步流程难点在于中间那步,压缩比例的计算,官网同样提供了个calculateInSampleSize方法其中reqWidth和reqHeight是所需图片限定最小宽高值/*** 计算压缩比例值* @param options 解析图片的配置信息* @param reqWidth 所需图片压缩尺寸最小宽度* @param reqHeight 所需图片压缩尺寸最小高度* @return*/public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {// 保存图片原宽高值final int height = options.outHeight;final int width = options.outWidth;// 初始化压缩比例为1int inSampleSize = 1;// 当图片宽高值任何一个大于所需压缩图片宽高值时,进入循环计算系统if (height > reqHeight || width > reqWidth) {final int halfHeight = height / 2;final int halfWidth = width / 2;// 压缩比例值每次循环两倍增加,// 直到原图宽高值的一半除以压缩值后都~大于所需宽高值为止while ((halfHeight / inSampleSize) >= reqHeight&& (halfWidth / inSampleSize) >= reqWidth) {inSampleSize *= 2;}}return inSampleSize;}利用此方法获取到所需压缩比例值,最终获取到压缩后的图片~以上代码能够看懂的话,下面这段/*扯淡*/可以跳过逻辑是将原图宽高一半一半的缩减,一直减到宽高都小于自己设定的限定宽高时为止,测试的时候问题来了原图400*300,我限定值200*150,if满足进入,while循环第一次,400/2/1=200不满足>的条件~结束循环,最终返回了个inSampleSize=1给我马丹我限定值正好是原图的一半啊,你应该返回给我2啊~你特么最后返回个1给我,那压缩处理后的图还是400*300!!!当我将限定值稍微改一下变成195*145稍微降低一点点时~if满足进入,while循环第一次,400/2/1>195满足~然后压缩比例1*2变成了2,在下一次while循环时不满足条件结束,最后返回比例值2~ 满足压缩预期官网的这个方法是: 将图片一半一半的压缩,直到压缩成成大于所需宽高数的那个最低值大于~不是大于等于,所以就会出现我上面那种情况,我觉得方法不是太好= = 能满足压缩的需求,但是压缩的比例不够准确~所以最好改成大于等于,如下(个人意见,仅供参考,在实际压缩中很少遇到恰巧等于的这个情况,所以>和>=差别也不大额~看我这扯扯淡就当对计算比例的逻辑加深个理解吧)while ((halfHeight / inSampleSize) >= reqHeight&& (halfWidth / inSampleSize) >= reqWidth) {inSampleSize *= 2;}优化:还是上面例子,如果限定了200*150,而原图是390*290会是个啥情况?还是第一次while循环,390/2/1结果是195不满足>200的情况,结束循环,比例值为1,最后图片压缩成400*300虽然压缩一次以后没有满足大于所需宽高,但是和所需宽高很接近啊!!!能不能做一个获取压缩成最接近所需宽高数的比例值呢?我也不知道= = 回头可以慢慢研究, 这个"接近"的定义比较模糊,不好掌握~找了几个有名的图片加载开源框架发现也都没有这种处理- -不知道是这样设计是不需要呢,还是没啥用呢以上,图片的像素大小已经做了缩放,但是图片的大小除了和像素有关,还和色彩样式有关不同的样式决定了图片单个像素占的字节数比如,图片默认的色彩样式为ARGB_8888,每个像素占4byte(字节)大小可以看到一共有四种色彩样式ALPHA_8 每个像素只要1字节~可惜只能代表透明度,没有颜色属性ARGB_4444 每个像素要2字节~带透明度的颜色~可惜官方不推荐使用了ARGB_8888 每个像素要4字节~带透明度的颜色, 默认色样RGB_565 每个像素要2字节~不带透明度的颜色默认为ARGB_8888,如果想丧心病狂的继续减少图片所占大小~不需要透明度参数的话,那就可以把色彩样式设为RGB_565设置方法是在BitmapFactory.decode..获取图片事例时修改配置参数的inPreferredConfig 参数opts.inPreferredConfig = Bitmap.Config. RGB_565 ;想亲自撸一撸试一试压缩图片了吧?要注意点问题,如果用res包下图片测试的话,你会发现有图片尺寸有点混乱那是因为在drawable-*dpi文件夹中的图片会根据对应对应的屏幕密度值不同自动进行一定的缩放,比如放在drawable-hdpi里的图片,直接不经过压缩BitmapFactor.decode..出来,会发现bitmap的宽高值是原图的2/3,测试的时候图片记得放在drawable包下(没有的话自己res下新建一个),否则你会被奇怪的宽高值弄凌乱的,具体变化原因参考源代码处理,或者网上搜搜看。

自定义lru算法缓存

自定义lru算法缓存

自定义lru算法缓存要说起LRU缓存,可能很多小伙伴一听就懵了。

哎呀,啥是LRU?咋听着有点像“老百姓认不住”的缩写?LRU可不是个让你摸不着头脑的东西,它指的是“最近最少使用”算法,英文全称就是Least Recently Used。

简单来说,就是一个缓存策略,用来管理有限的内存空间,避免内存被占满导致程序卡顿,或者最可怕的崩溃。

你想啊,咱们手机里不也是这么管理内存的吗?微信、QQ这些社交软件,有时候打开的速度就慢得让人抓狂。

这不,你一关掉几个常用APP,剩下的才能跑得飞快。

LRU缓存就差不多是这个原理。

它的基本规则就是:咱们存储的数据越多,越容易发生拥挤。

这时候,LRU会“聪明”地决定哪些数据不重要,哪些是最近没怎么用过的,反正占个地方也没啥用,那就淘汰掉。

想象一下你在家里,有一堆书。

每天都有人借,借来借去。

你最爱的那本《三国演义》,当然得放在书架最显眼的地方,一拿就能用。

而那些放在角落里,半年都没人碰的书,早晚会被清理掉。

LRU就像你的家庭图书管理员,专门记住哪个书是最常借的,哪个书你再看也没兴趣,最后把它们“清空”掉,腾出地方给新书。

好吧,咱们不说那么多抽象的东西,咱从生活中的小事儿聊聊。

比如你去超市,买了一大堆东西。

结果,卡车后备箱太小,最后你只能选择把最不重要的几个东西放弃。

这就是LRU的简化版:只有有限的空间,聪明地挑选哪些东西该留下,哪些该丢掉。

这个LRU算法本质上就是依靠时间来判断的。

你用过的数据,时间一长自然会被认定为“冷门”数据,而最近用过的就成了“热门”数据。

你能想象吧,就像你手机里的那几款APP,哪个最常用,哪个用得少,一眼就能看出来,完全不用问。

LRU的核心思想就是:缓存中始终保存最“热门”的数据,而那些被丢到一边很久的,不值一提的就“淘汰”掉。

说到这里,也许你会问:“那这LRU缓存和我们平时电脑上缓存有啥不一样?”这俩没什么太大差别。

你可以把LRU当作是一种“聪明”的缓存策略,能够最大化地利用有限的内存空间。

【推荐下载】Android图片缓存之初识Glide

【推荐下载】Android图片缓存之初识Glide

Android 图片缓存之初识Glide2016/06/04 0 前言:前面总结学习了图片的使用以及Lru 算法,今天来学习一下比较优秀的图片缓存开源框架。

技术本身就要不断的更迭,从最初的自己使用SoftReference 实现自己的图片缓存,到后来做电商项目自己的实现方案不能满足项目的需求改用Afinal,由于Afinal 不再维护而选择了师出同门的Xutils,中间也接触过别的开源框架比如Picasso,对Picasso 的第一次印象就不太好,初次接触是拿到了公司刚从外包公司接手过来的图片社交类app,对内存占用太大,直接感受就是导致ListView 滑动有那么一点卡顿,老牌的图片缓存框架universalImageLoader 听说过一直没有真正使用过,之前项目都很小,差不多几百万级别的app,一直使用的都是Xutils,最近觉得项目大起来了,万一Xutils 不维护了或者说要求支持的图片格式多起来的时候,可能Xutils 就不是最佳选择了,这也是来学习Gilde 的根本动机吧。

其实本来想着去学习Facebook 的Fresco 图片框架,但是简单的看了一下,需要连同自定义控件一起使用,功能虽然强大,但是对于已经在维护的项目修改成本那可不是一般的高,以后有兴趣在学习吧!图片缓存相关博客地址:Android 图片缓存之Bitmap 详解Android 图片缓存之初识GlideAndroid 图片缓存之Glide 进阶Android 图片缓存之Lru 算法Glide 简介:Glide 是Google 员工的开源项目,Google I/O 上被推荐使用,一个高效、开源、Android 设备上的媒体管理框架,它遵循BSD、MIT 以及Apache 2.0 协议发布。

Glide 具有获取、解码和展示视频剧照、图片、动画等功能,它还有灵活的API,这些API 使开发者能够将Glide 应用在几乎任何网络协议栈里。

图片缓存之内存缓存技术LruCache

图片缓存之内存缓存技术LruCache

图片缓存之内存缓存技术LruCache,软引用每当碰到一些大图片的时候,我们如果不对图片进行处理就会报OOM异常,这个问题曾经让我觉得很烦恼,后来终于得到了解决,那么现在就让我和大家一起分享一下吧。

这篇博文要讲的图片缓存机制,我接触到的有两钟,一种是软引用,另一种是内存缓存技术。

先来看下两者的使用方式,再来作比较。

除了加载图片时要用到缓存处理,还有一个比较重要的步骤要做,就是要先压缩图片。

1、压缩图片至于要压缩到什么状态就要看自己当时的处境了,压缩图片的时候既要达到一个小的值,又不能让其模糊,更不能拉伸图片。

1./**2. * 加载内存卡图片3. */4. BitmapFactory.Options options =new BitmapFactory.Options();5. options.inJustDecodeBounds = true;// 设置了此属性一定要记得将值设置为false6. Bitmap bitmap =null;7. bitmap = BitmapFactory.decodeFile(url, options);8.int be =(int)((options.outHeight > options.outWidth ? options.outHeight / 1509.: options.outWidth / 200));10.if(be <= 0)// 判断200是否超过原始图片高度11. be = 1;// 如果超过,则不进行缩放12. options.inSampleSize = be;13. options.inPreferredConfig = Bitmap.Config.ARGB_4444;14. options.inPurgeable = true;15. options.inInputShareable = true;16. options.inJustDecodeBounds = false;17.try{18. bitmap = BitmapFactory.decodeFile(url, options);19.}catch(OutOfMemoryError e){20.System.gc();21.Log.e(TAG,"OutOfMemoryError");22.}2、软引用:只要有足够的内存,就一直保持对象,直到发现内存吃紧且没有Strong Ref时才回收对象。

【Android开发Wiki】进阶篇高效的显示位图(三)—缓存位图

【Android开发Wiki】进阶篇高效的显示位图(三)—缓存位图

其余的活动或者应用程序都是很耗内存的嘛?
大量的图片是如何立刻出现在屏幕上的?需要多少即将在屏幕上显示的?
设备的屏幕的大小和分辨率是多少?一个额外的高密度屏(xhdpi)设备,例如Galaxy Nexus 将需要一个更大的缓存来维持内存中相同数量的图片,与像Nexus S(hdpi)设备比较起来.
位图是什么尺寸和配置以及每张图片要占用多少内存?
图片访问频繁嘛?比起别的将会被频繁地访问吗?也许你可能总是想要在内存中保存一定项,甚至对于不同的位图组来说有多个LRUCache对象.
你能在数量和质量之间取得平衡嘛?有时对于存储更多的低质量的位图是更有用的,潜在地在另外的后台任务中加载一个更高质量版本.
没有具体的大小以及适合所有应用程序的公式,它是由你来分析您的使用情况,并拿出一个合适的解决方案.缓存太小会导致额外的没有益处的开销,缓存过大会再次导致ng.
情况下,由于图片填充到activity时几乎马上从内存加载,你应当注意到几乎没有滞后的感觉.任何图片都是先在内存缓存中找,没有的话再从磁盘缓存中找,如果都没有的话,就会像往常获取图片一样处理.
文章来源:/page/Caching_Bitmaps。

lru应用场景

lru应用场景

lru应用场景LRU(Least Recently Used,最近最少使用)是常见的一种缓存算法,它的核心思想是在缓存满时,优先淘汰最近最少用的缓存项。

LRU广泛应用于电子商务、科技、金融和社交等行业,以下是几个应用场景。

一、网站页面缓存LRU算法被广泛应用于网站的页面缓存中,例如针对流量较大的电商品牌网站。

对于这类网站,用户访问频率高,缓存需要经常刷新且占用大量的内存空间。

使用LRU可以确保在内存空间不够时,优先保留最活跃、最常用的缓存页面,便于快速响应用户请求。

通过LRU算法可以减少服务器负载,并加速页面加载速度。

同时,它还可以优化用户体验,使用户感受到更流畅的页面浏览。

二、图片缓存随着智能手机的普及,图片在移动应用中扮演越来越重要的角色。

然而,图片占用内存大,因此需要尽可能压缩图片的内存占用。

通过LRU算法,可以在内存不够用时,快速清除内存占用率高的图片,并将最近最少使用的图片替换掉。

当用户下次打开应用时,缓存中已经过期的图片将重新从服务器加载,就不需要再次从内存加载,减少了内存使用。

三、数据结构缓存对于大多数企业级应用,基于内存的缓存是必不可少的。

数据结构缓存通过将数据保存在内存中,提高了应用程序的响应速度。

LRU算法可以在实现数据结构缓存时使用,保证最近最常用的数据被保留在内存中,以便快速访问。

同时使用LRU算法可以有效减少内存使用并提高程序的运行效率。

四、数据库缓存数据库查询是企业级应用程序中常见而重要的部分。

在处理高并发的请求时,常常是使用缓存来优化性能。

通过LRU算法的数据库缓存,可以快速定位查询中经常使用的数据,并将它们添加到缓存中。

缓存中存储的数据将被频繁使用,避免了重复查询,减少了数据库服务器的负载。

总之,LRU算法在众多应用场景中起到了重要的作用。

它可以确保增加系统的性能,减少内存使用,并改进用户的体验。

虽然它可能存在一些限制,例如对于不断更新的数据缓存效果较差,但对于需要快速响应的数据查询和访问,LRU算法是一项不可或缺的技术。

Android中Glide加载库的图片缓存配置究极指南

Android中Glide加载库的图片缓存配置究极指南

Android中Glide加载库的图⽚缓存配置究极指南零、选择Glide为什么图⽚加载我⾸先推荐Glide?图⽚加载框架⽤了不少,从afinal框架的afinalBitmap,Xutils的BitmapUtils,⽼牌框架universalImageLoader,著名开源组织square的picasso,google推荐的glide到FaceBook推出的fresco。

这些我前前后后都体验过,那么⾯对这么多的框架,该如何选择呢?下⾯简单分析下我的看法。

afinal和Xuils在github上作者已经停⽌维护了,开源社区最新的框架要属KJFramework,不过这种快速开发框架看似很好⽤,功能也应有尽有,⼩型项⽬也罢,⼤型项⽬我不是很推荐,这样做项⽬的耦合度太⾼,⼀旦出现停⽌维护,⽽新的问题不断增加,没⼈处理就⿇烦了。

在glide和fresco还未出来的时候,当时最⽕的莫过于universalImageLoader和picasso了,当时觉得universalImageLoader配置相对picasso⿇烦,虽然提供了各种配置,但是没有实践过,根本不知道如何配置,还不如都采⽤默认配置,就选择了picasso作为图⽚加载框架,⽤了近⼀年的时间,没有太⼤的问题,且使⽤简单,或许是因为之前的项⽬太过于简单,周期也并不是很长,还有使⽤eclipse开发,⼀个很⼤的问题⼀直都没有暴露出来,换上了最新的Android Studio可以清晰的看到各种性能相关的监控,如cpu还有内存监控,终于知道了之前做的项⽬都那么的卡顿的罪魁祸⾸,picasso加载稍微⼤⼀点的图⽚就特别耗内存,通常⼀个listView或者顶部滑动⼴告栏都含有多张图⽚,这使得做出的页⾯只要含图⽚较多就异常卡顿(之前的时候还把它归结为测试机不好),知道这⼀点后我就有点想把picasso给替换掉,但这⼀次我不能那么粗⼼。

测试了picasso,glide,universalImageLoader,fresco这四个框架,测试内容⼤概有以下⼏项,内存测试,⼤图⽚测试,⼩图⽚测试,本地图⽚,⽹络图⽚当然还结合官⽅⽂档体验其特⾊功能,内存测试中,glide,universalImageLoader,fresco表现都⾮常优秀,picasso这⼀点上实在是太糟糕了,⼩图⽚差别也不是很⼤,稍微⼤点图⽚内存消耗就要⽐其他⾼出⼏倍,这⼀点上证明了我的猜想,picasso不能再⽤了,下⾯⼀项项分析其他框架,在⾼于2M左右⼤图测试中fresco的表现则和picasso ⼀样直接神马都不显⽰,项⽬中要实现⼤图预览功能,这点上是不⾏的,接着看universalImageLoader和glide在这⼏项测试中成绩都很好,到底该如何选择呢?因为我项⽬之前⽤的picasso,glide从⽤法上⼏乎就是另⼀个picasso,从picasso转移到glide相对改动较少,还有⼀点就是这个项⽬是google在维护,我也能给它更多的信任,相⽐较universalImageLoader,glide可以⽀持gif和短视频,后期也需要⽤到,这⾥不得不谈⼀下glide优秀的缓存机制了,glide图⽚缓存默认使⽤RGB565相当于ARGB8888可以节省不少的空间,⽀持与activity,fragment,application⽣命周期的联动,更智能管理图⽚请求当然还有其他的扩展更多可以看?glide介绍?当然,glide的⽅法数量⽐universalImageLoader多了1000多个,遇到64k问题的会⽐较关注这个。

【推荐下载】Android 文件缓存方法

【推荐下载】Android 文件缓存方法

Android 文件缓存方法2016/02/01 38642 前言我们经常遇到从网络获取图片,为了使图片查看流畅,我们肯定要使用缓存,大部分我们会使用内存缓存,但是android 内存缓存毕竟是有限的,这样的话,我们必须使用文件来缓存部分图片。

思路当我们把一张图片从网络下载成功以后,这个图片会被加入内存缓存和文件缓存,内存缓存来说请参考Android 内存溢出大总结,对于文件缓存来说,这张图片将被以url 的哈希值加cach 后缀名的形式存储在SD 卡上,这样,当下一次再需要同一个url 的图片的时候,就不需要从网络下载了,而是直接通过url 来进行查找。

同时一张图片被访问时,它的最后修改时间将被更新,这样的意义在于:当SD卡空间不足的时候,将会按照最后修改时间来删除40%缓存的图片,确切来说,那些修改时间比较早的图片将会被删除。

package com.ty.highway.highwaysystem.support.utils.cache;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.Environment;import android.os.StatFs;import android.util.Log;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStream;import java.util.Arrays;import parator;/** * Created by fuweiwei on 2016/1/26. * 文件缓存* 内存缓存是有限的,其它的文件缓存,当文件缓存操作一定量时我们删除之前的缓存*/public class ImageFileCache{ private static final String TAG = “ImageFileCache”;//图片缓存目录private static final String IMGCACHDIR = “/sdcard/ImgCach”; //保存的cache 文件宽展名private static final String CACHETAIL = “.cach”; private static final int MB = 1024*1024; private static final int CACHE_SIZE = 1; //当SD 卡剩余空间小于10M 的时候会清理缓存private static final int FREE_SD_SPACE_NEEDED_TO_CACHE = 10; public ImageFileCache() { //清理部分文件缓存removeCache(IMGCACHDIR); } /** * 从缓存中获取图片*/ public Bitmap。

Android处理网络和图片的工具类

Android处理网络和图片的工具类

Android处理网络和图片的工具类1:网络的底层环境采用apache 的httpClient 链接池框架2:图片缓存采用基于LRU 的算法3:网络接口采用监听者模式4 包含图片的OOM 处理(及时回收处理技术的应用)import java.io.FilterInputStream;import java.io.IOException;import java.io.InputStream;import ng.ref.SoftReference;import java.util.HashMap;import java.util.concurrent.RejectedExecutionException;import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.HttpStatus;import org.apache.http.client.methods.HttpGet;import xiaogang.enif.utils.HttpManager;import xiaogang.enif.utils.IOUtils;import xiaogang.enif.utils.LogUtils;import xiaogang.enif.utils.LruCache;import android.app.ActivityManager;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.BitmapFactory.Options;import android.graphics.Canvas;import android.graphics.drawable.BitmapDrawable;import android.os.AsyncTask;import android.text.TextUtils;import android.util.AttributeSet;import android.widget.ImageView;public class CacheView extends ImageView {private static final int DEFAULT_RES_ID = 0;private int mDefaultImage = DEFAULT_RES_ID;private static LruCache<String, Bitmap> mLruCache;private static HashMap<Integer, SoftReference<Bitmap>> mResImage;private Context mContext;private LogUtils mLog = LogUtils.getLog(CacheView.class);public CacheView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);init(context);}public CacheView(Context context, AttributeSet attrs) { super(context, attrs);init(context);}public CacheView(Context context) {super(context);init(context);}private void init(Context context) {mContext = context;if (mLruCache == null) {final int cacheSize = getCacheSize(context);mLruCache = new LruCache<String, Bitmap>(cacheSize) { @Overrideprotected int sizeOf(String key, Bitmap bitmap) {// The cache size will be measured in bytes rather than// number of items.return bitmap.getRowBytes() * bitmap.getHeight(); }@Overrideprotected void entryRemoved(boolean evicted, String key, Bitmap oldValue,Bitmap newValue) {if (evicted && oldValue != null&& !oldValue.isRecycled()) {oldValue.recycle();oldValue = null;}}};}if (mResImage == null) {mResImage = new HashMap<Integer,SoftReference<Bitmap>>();}}@Overrideprotected void onDraw(Canvas canvas) {BitmapDrawable drawable = (BitmapDrawable)getDrawable();if (drawable == null) {setDefaultImage();} else {if (drawable.getBitmap() == null ||drawable.getBitmap().isRecycled()) {setDefaultImage();}}try {super.onDraw(canvas);} catch(RuntimeException ex) {}}public void setImageUrl(String url, int resId) { setTag(url);Bitmap bitmap = getBitmapFromCache(url);if (bitmap == null || bitmap.isRecycled()) {mDefaultImage = resId;setDefaultImage();try {new DownloadTask().execute(url);} catch (RejectedExecutionException e) {// do nothing, just keep not crash}} else {setImageBitmap(bitmap);}}private void setDefaultImage() {if (mDefaultImage != DEFAULT_RES_ID) {setImageBitmap(getDefaultBitmap(mContext)); }}private Bitmap getDefaultBitmap(Context context) {SoftReference<Bitmap> loading =mResImage.get(mDefaultImage);if (loading == null || loading.get() == null ||loading.get().isRecycled()) {loading = newSoftReference<Bitmap>(BitmapFactory.decodeResource(context.getResources(), mDefaultImage));mResImage.put(mDefaultImage, loading);}return loading.get();}private class DownloadTask extends AsyncTask<String, Void, Bitmap> {private String mParams;@Overridepublic Bitmap doInBackground(String... params) {mParams = params[0];final Bitmap bm = download(mParams);addBitmapToCache(mParams, bm);return bm;}@Overridepublic void onPostExecute(Bitmap bitmap) {String tag = (String)getTag();if (!TextUtils.isEmpty(tag) && tag.equals(mParams)) { if (bitmap != null) {setImageBitmap(bitmap);}}}};/** An InputStream that skips the exact number of bytes provided, unless it* reaches EOF.*/static class FlushedInputStream extends FilterInputStream { public FlushedInputStream(InputStream inputStream) { super(inputStream);}@Overridepublic long skip(long n) throws IOException {long totalBytesSkipped = 0L;while (totalBytesSkipped < n) {long bytesSkipped = in.skip(n - totalBytesSkipped);if (bytesSkipped == 0L) {int b = read();if (b < 0) {break; // we reached EOF} else {bytesSkipped = 1; // we read one byte}}totalBytesSkipped += bytesSkipped;}return totalBytesSkipped;}}private Bitmap download(String url) {InputStream in = null;HttpEntity entity = null;Bitmap bmp = null;try {final HttpGet get = new HttpGet(url);final HttpResponse response =HttpManager.execute(mContext, get);if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {entity = response.getEntity();in = entity.getContent();try {bmp = getDecodeBitmap(in, url);} catch (OutOfMemoryError err) {Runtime.getRuntime().gc();bmp = getDecodeBitmap(in, url);}} else {get.abort();return bmp;}addBitmapToCache(url, bmp);} catch (IOException e) {return bmp;} finally {IOUtils.closeStream(in);}return bmp;}private final Bitmap getDecodeBitmap(InputStream in, String url) {Options options = new Options();options.inPurgeable = true;options.inInputShareable = true;return BitmapFactory.decodeStream(new FlushedInputStream(in), null, options);}private final void addBitmapToCache(String url, Bitmap bitmap) { if (bitmap != null) {mLruCache.put(url, bitmap);Runtime.getRuntime().gc();}}private final Bitmap getBitmapFromCache(String url) { return mLruCache.get(url);}private int getCacheSize(Context context) {// According to the phone memory, set a proper cache size for LRU cache// dynamically.final ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);final int memClass = am.getMemoryClass();int cacheSize;if (memClass <= 24) {cacheSize = (memClass << 20) / 24;} else if (memClass <= 36) {cacheSize = (memClass << 20) / 18;} else if (memClass <= 48) {cacheSize = (memClass << 20) / 12;} else {cacheSize = (memClass << 20) >> 3;}mLog.debug("cacheSize == "+cacheSize);System.out.println("cacheSize == "+cacheSize);return cacheSize;}public static void recycle() {if (mLruCache != null && !mLruCache.isEmpty()) {mLruCache.evictAll();mLruCache = null;}if (mResImage != null) {for(SoftReference<Bitmap> reference : mResImage.values()) {Bitmap bitmap = reference.get();if (bitmap != null && !bitmap.isRecycled()) {bitmap.recycle();bitmap = null;}}mResImage = null;}}}说明:1)entryRemoved 在做Bitmap recyle 的时候的三个条件缺一不可2)onDraw 里面判断图片是否被回收,如果回收需要设置默认的图片3)add bitmap 到cache 的时候 Runtime.getRuntime().gc 的调用</pre>。

内存缓存-LruCache与压缩图片

内存缓存-LruCache与压缩图片

内存缓存-LruCache与压缩图⽚LruCache这个类⾮常适合⽤来缓存图⽚,它的主要算法原理是把最近使⽤的对象⽤强引⽤存储在 LinkedHashMap 中,并且把最近最少使⽤的对象在缓存值达到预设定值之前从内存中移除.与它对应的是DiskLruCache(磁盘缓存)我们在编写Android程序的时候经常要⽤到许多图⽚,不同图⽚总是会有不同的形状、不同的⼤⼩,但在⼤多数情况下,这些图⽚都会⼤于我们程序所需要的⼤⼩。

⽐如说系统图⽚库⾥展⽰的图⽚⼤都是⽤⼿机摄像头拍出来的,这些图⽚的分辨率会⽐我们⼿机屏幕的分辨率⾼得多。

⼤家应该知道,我们编写的应⽤程序都是有⼀定内存限制的,程序占⽤了过⾼的内存就容易出现OOM(OutOfMemory)异常。

我们可以通过下⾯的代码看出每个应⽤程序最⾼可⽤内存是多少int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);System.out.println("Max memory is " + maxMemory + "KB");//模拟器输出:16384kB因此在展⽰⾼分辨率图⽚的时候,最好先将图⽚进⾏压缩。

压缩后的图⽚⼤⼩应该和⽤来展⽰它的控件⼤⼩相近,在⼀个很⼩的ImageView上显⽰⼀张超⼤的图⽚不会带来任何视觉上的好处,但却会占⽤我们相当多宝贵的内存,⽽且在性能上还可能会带来负⾯影响。

下⾯我们就来看⼀看,如何对⼀张⼤图⽚进⾏适当的压缩,让它能够以最佳⼤⼩显⽰的同时,还能防⽌OOM的出现。

BitmapFactory这个类提供了多个解析⽅法(decodeByteArray, decodeFile, decodeResource等)⽤于创建Bitmap对象,我们应该根据图⽚的来源选择合适的⽅法。

⽐如SD卡中的图⽚可以使⽤decodeFile⽅法,⽹络上的图⽚可以使⽤decodeStream⽅法,资源⽂件中的图⽚可以使⽤decodeResource⽅法。

Android缓存之DiskLruCache磁盘缓存的使用

Android缓存之DiskLruCache磁盘缓存的使用

Android缓存之DiskLruCache磁盘缓存的使⽤DiskLruCache和LruCache不同的是,LruCache是内存缓存,⽽DiskLruCache是指磁盘缓存,顾名思义就是把⽂件缓存到磁盘,也也就是⼿机的内存卡中。

接下来先简单介绍DiskLruCache的使⽤⽅法。

下载源码然后把源码中的三个类拷贝到⼯程中。

DiskLruCache常⽤⽅法:⽅法备注DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)打开⼀个缓存⽬录,如果没有则⾸先创建它,directory:指定数据缓存地址 appVersion:APP版本号,当版本号改变时,缓存数据会被清除 valueCount:同⼀个key可以对应多少⽂件 maxSize:最⼤可以缓存的数据量Editor edit(String key)通过key可以获得⼀个DiskLruCache.Editor,通过Editor可以得到⼀个输出流,进⽽缓存到本地存储上void flush()强制缓冲⽂件保存到⽂件系统Snapshot get(String key)通过key值来获得⼀个Snapshot,如果Snapshot存在,则移动到LRU队列的头部来,通过Snapshot可以得到⼀个输⼊流InputStreamlong size()缓存数据的⼤⼩,单位是byteboolean remove(Stringkey)根据key值来删除对应的数据,如果该数据正在被编辑,则不能删除void delete()关闭缓存并且删除⽬录下所有的缓存数据,即使有的数据不是由DiskLruCache 缓存到本⽬录的void close()关闭DiskLruCache,缓存数据会保留在外存中boolean isClosed()判断DiskLruCache是否关闭,返回true表⽰已关闭File getDirectory()缓存数据的⽬录初始化缓存对象接下来具体介绍DiskLruCache的简单⽅法。

glide的三级缓存原理

glide的三级缓存原理

glide的三级缓存原理Glide是一款Android平台上的图片加载库,它的三级缓存机制是其核心特性之一。

下面将详细介绍Glide的三级缓存原理。

一、Glide的三级缓存机制Glide的三级缓存机制包括内存缓存、磁盘缓存和网络缓存。

当我们使用Glide加载图片时,它会先从内存缓存中查找是否有该图片的缓存,如果有,则直接从内存中读取并显示;如果没有,则从磁盘缓存中查找是否有该图片的缓存,如果有,则将其加载到内存缓存中并显示;如果磁盘缓存中也没有该图片的缓存,则从网络中下载该图片,并将其保存到磁盘缓存和内存缓存中,并显示出来。

二、内存缓存内存缓存是Glide的第一级缓存,它的作用是将经常使用的图片缓存到内存中,以便快速读取和显示。

Glide使用了LruCache算法来管理内存缓存,LruCache是一种基于最近最少使用原则的缓存算法,它会将最近最少使用的缓存对象从缓存中移除,以保证缓存的有效性和性能。

三、磁盘缓存磁盘缓存是Glide的第二级缓存,它的作用是将不常使用的图片缓存到磁盘中,以便下次快速读取和显示。

Glide使用了DiskLruCache算法来管理磁盘缓存,DiskLruCache是一种基于LRU算法的磁盘缓存算法,它将缓存对象保存到磁盘文件中,并使用文件名作为缓存的key值,以保证缓存的唯一性和有效性。

四、网络缓存网络缓存是Glide的第三级缓存,它的作用是在内存缓存和磁盘缓存都没有该图片的缓存时,从网络中下载该图片,并将其保存到磁盘缓存和内存缓存中。

Glide使用了OkHttp库来管理网络缓存,OkHttp 是一款高效的HTTP客户端库,它支持HTTP/2协议和SPDY协议,能够快速地下载和缓存图片。

五、总结Glide的三级缓存机制是其核心特性之一,它能够快速地加载和显示图片,并且能够有效地减少网络请求和提高应用性能。

通过内存缓存、磁盘缓存和网络缓存的组合使用,Glide能够实现快速、高效、稳定的图片加载和显示,是Android平台上不可缺少的图片加载库之一。

glide的原理

glide的原理

glide的原理Glide是一款用于Android平台的图片加载库,它的核心原理是通过智能地管理内存和网络请求,提供高效的图片加载和显示功能。

本文将从Glide的工作流程、内存管理、网络请求以及优化策略等方面来详细介绍Glide的原理。

一、Glide的工作流程Glide的工作流程可以分为加载图片和显示图片两个阶段。

首先,当我们调用Glide的load()方法加载图片时,Glide会根据传入的图片地址生成一个唯一的key,并从内存缓存中查找对应的图片资源。

如果内存缓存中存在该图片资源,则直接将图片显示到目标View上;如果内存缓存中不存在该图片资源,则继续执行后续的操作。

接下来,Glide会判断磁盘缓存中是否存在该图片资源。

如果磁盘缓存中存在该图片资源,Glide会将图片解码为Bitmap,并将Bitmap添加到内存缓存中,然后再将图片显示到目标View上;如果磁盘缓存中也不存在该图片资源,则继续执行后续的操作。

Glide会通过网络请求将图片下载到本地,并将图片解码为Bitmap。

然后,Glide将Bitmap添加到内存缓存和磁盘缓存中,并将图片显示到目标View上。

在整个过程中,Glide会根据需要调整图片的大小和质量,以提供更好的用户体验。

二、Glide的内存管理Glide通过内存缓存来管理已加载的图片资源,以避免重复加载和浪费内存。

它使用LruCache算法来实现内存缓存,该算法会根据图片的大小和使用频率来动态调整缓存空间的大小。

具体而言,Glide会根据图片的像素大小和格式计算出每个图片所占用的内存大小,并将这些图片存储在一个LruCache中。

当内存缓存中的图片数量超过了设定的阈值时,Glide会自动删除最近最少使用的图片,以保证缓存空间的有效利用。

除了内存缓存之外,Glide还通过磁盘缓存来管理已下载的图片资源。

它使用DiskLruCache算法来实现磁盘缓存,该算法会将图片存储在应用程序的私有目录中,以防止其他应用程序访问和修改图片资源。

android 网络加载图片 对图片资源进行优化 并且实现内存双缓存 磁盘缓存

android 网络加载图片  对图片资源进行优化   并且实现内存双缓存   磁盘缓存

android 网络加载图片,对图片资源进行优化,并且实现内存双缓存+ 磁盘缓存经常会用到网络文件比如查看大图片数据资源优化的问题,当然用开源的项目 Android-Universal-Image-Loader 或者ignition 都是个很好的选择。

在这里把原来写过的优化的代码直接拿出来,经过测试千张图片效果还是不错的。

工程目录:至于Activity 就是加载了1个网格布局[java]view plaincopy1./**2. * 实现异步加载和 2级缓存3. */4.public class ImagedownActivity extends Activity {5.6.public static String filepath;7.@Override8.public void onCreate(Bundle savedInstanceState) {9.super.onCreate(savedInstanceState);10. setContentView(yout.main);11. filepath = this.getCacheDir().getAbsolutePath();12. GridView gv=(GridView)findViewById(R.id.gridview01);13.//设置列数14. gv.setNumColumns(3);15.//配置适配器16. gv.setAdapter(new Myadapter(this));17. }18.19.@Override20.protected void onDestroy() {21.// TODO Auto-generated method stub22.//activity 销毁时,清除缓存23. MyImageLoader.removeCache(filepath);24.super.onDestroy();25. }26.27.}接下来Myadapter.java(给网格每个item塞入图片)在生成每个item 异步请求网络获取image [java]view plaincopy1.public class Myadapter extends BaseAdapter {2.private Context context;3.private String root ="http://192.168.0.100:8080/Android_list/";4.private String[] URLS;5.private final MyImageLoader myImageLoader = new MyImageLoader(context);;6.7./**8. * adapter 初始化的时候早一堆数据9. * 这里我请求的是自己搭的服务器10. * @param context11. */12.public Myadapter(Context context){13.this.context =context;14. URLS = new String[999];15.for (int i = 0; i < 999; i++) {16. URLS[i] = root + (i+1)+".jpg";17. }18. }19.20.21.@Override22.public int getCount() {23.return URLS.length;24. }25.26.@Override27.public Object getItem(int position) {28.return URLS[position];29. }30.31.@Override32.public long getItemId(int position) {33.return URLS[position].hashCode();34. }35.36.37.38.@Override39.public View getView(int position, View view, ViewGroup parent) {40. ImageView imageView;41.if(view==null){42. imageView=new ImageView(context);43. imageView.setLayoutParams(new youtParams(200,190));44. imageView.setAdjustViewBounds(false);45. imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);46. imageView.setPadding(5, 5, 5, 5);47. }else{48. imageView=(ImageView)view;49. }50. myImageLoader.downLoad(URLS[position], (ImageView)imageView , context);51.return imageView;52. }53.}MyImageLoader.java[java]view plaincopy1.public class MyImageLoader {2.3.//最大内存4.final static int memClass = (int) Runtime.getRuntime().maxMemory();5.private Context context;6.7.// 是否缓存到硬盘8.private boolean diskcache = true;9.10.// 定义一级缓存的图片数11.private static final int catch_num = 10;12.13.// 定义二级缓存容器软引用14.private static ConcurrentHashMap<String, SoftReference<Bitmap>> current_hashmap = new ConcurrentHashMap<String, SoftReference<Bitmap>>();15.16.// 定义一级缓存容器强引用 (catch_num ,0.75f,true)默认参数2.加载因子默认3.排序模式 true17.private static LinkedHashMap<String, Bitmap> link_hashmap = new LinkedHashMap<String, Bitmap>(catch_num ,0.75f,true) {18.19.// 必须实现的方法20.protected boolean removeEldestEntry(java.util.Map.Entry<String, Bitmap> eldest) {21./** 当一级缓存中图片数量大于定义的数量放入二级缓存中22. */23.if (this.size() > catch_num) {24.// 软连接的方法存进二级缓存中25. current_hashmap.put(eldest.getKey(), new SoftReference<Bitmap>(26. eldest.getValue()));27.//缓存到本地28. cancheToDisk(eldest.getKey(),eldest.getValue() );29.30.return true;31. }32.return false;33. };34. };35.36.public MyImageLoader(Context context) {37.38. }39.40.41./**42. * 外部调用此方法进行下载图片43. */44.public void downLoad(String key , ImageView imageView,Context context){45.// 先从缓存中找。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Android使用 LruCache 缓存图片
使用图片缓存技术
在你应用程序的UI界面加载一张图片是一件很简单的事情,但是当你需要在界面上加载一大堆图片的时候,情况就变得复杂起来。

在很多情况下,(比如使用ListView, GridView 或者 ViewPager 这样的组件),屏幕上显示的图片可以通过滑动屏幕等事件不断地增加,最终导致OOM。

为了保证内存的使用始终维持在一个合理的范围,通常会把被移除屏幕的图片进行回收处理。

此时垃圾回收器也会认为你不再持有这些图片的引用,从而对这些图片进行GC操作。

用这种思路来解决问题是非常好的,可是为了能让程序快速运行,在界面上迅速地加载图片,你又必须要考虑到某些图片被回收之后,用户又将它重新滑入屏幕这种情况。

这时重新去加载一遍刚刚加载过的图片无疑是性能的瓶颈,你需要想办法去避免这个情况的发生。

这个时候,使用内存缓存技术可以很好的解决这个问题,它可以让组件快速地重新加载和处理图片。

下面我们就来看一看如何使用内存缓存技术来对图片进行缓存,从而让你的应用程序在加载很多图片的时候可以提高响应速度和流畅性。

内存缓存技术对那些大量占用应用程序宝贵内存的图片提供了快速访问的方法。

其中最核心的类是LruCache (此类在android-support-v4的包中提供) 。

这个类非常适合用来缓存图片,它的主要算法原理是把最近使用的对象用强引用存储在 LinkedHashMap 中,并且把最近最少使用的对象在缓存值达到预设定值之前从内存中移除。

在过去,我们经常会使用一种非常流行的内存缓存技术的实现,即软引用或弱引用(SoftReference or WeakReference)。

但是现在已经不再推荐使用这种方式了,因为从Android 2.3 (API Level 9)开始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象,这让软引用和弱引用变得不再可靠。

另外,Android 3.0 (API Level 11)中,图片的数据会存储在本地的内存当中,因而无法用一种可预见的方式将其释放,这就有潜在的风险造成应用程序的内存溢出并崩溃。

为了能够选择一个合适的缓存大小给LruCache, 有以下多个因素应该放入考虑范围内,例如:
你的设备可以为每个应用程序分配多大的内存?
设备屏幕上一次最多能显示多少张图片?有多少图片需要进行预加载,因为有可能很快也会显示在屏幕上?
你的设备的屏幕大小和分辨率分别是多少?一个超高分辨率的设备(例如 Galaxy Nexus) 比起一个较低分辨率的设备(例如 Nexus S ),在持有相同数量图片的时候,需要更大的缓存空间。

图片的尺寸和大小,还有每张图片会占据多少内存空间。

图片被访问的频率有多高?会不会有一些图片的访问频率比其它图片要高?如果有的话,你也许应该让一些图片常驻在内存当中,或者使用多个LruCache 对象来区分不同组的图片。

你能维持好数量和质量之间的平衡吗?有些时候,存储多个低像素的图片,而在后台去开线程加载高像素的图片会更加的有效。

并没有一个指定的缓存大小可以满足所有的应用程序,这是由你决定的。

你应该去分析程序内存的使用情况,然后制定出一个合适的解决方案。

一个太小的缓存空间,有可能造成图片频繁地被释放和重新加载,这并没有好处。

而一个太大的缓存空间,则有可能还是会引起 ng.OutOfMemory 的异常。

下面是一个使用 LruCache 来缓存图片的例子:
[java]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 private LruCache<String, Bitmap> mMemoryCache;
@Override
protected void onCreate(Bundle savedInstanceState) {
// 获取到可用内存的最大值,使用内存超出这个值会引起OutOfMemory 异常。

// LruCache 通过构造函数传入缓存值,以KB 为单位。

int maxMemory = (int ) (Runtime.getRuntime().maxMemory() / 1024); // 使用最大可用内存值的1/8作为缓存的大小。

int cacheSize = maxMemory / 8;
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
// 重写此方法来衡量每张图片的大小,默认返回图片数量。

return bitmap.getByteCount() / 1024;
}
15 16 17 18 19 20 21 22 23 24 25 26 };
}
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (getBitmapFromMemCache(key) == null ) {
mMemoryCache.put(key, bitmap);
}
}
public Bitmap getBitmapFromMemCache(String key) {
return mMemoryCache.get(key);
}
在这个例子当中,使用了系统分配给应用程序的八分之一内存来作为缓存大小。

在中高配置的手机当中,这大概会有4兆(32/8)的缓存空间。

一个全屏幕的 GridView 使用4张 800x480分辨率的图片来填充,则大概会占用1.5兆的空间(800*480*4)。

因此,这个缓存大小可以存储2.5页的图片。

当向 ImageView 中加载一张图片时,首先会在 LruCache 的缓存中进行检查。

如果找到了相应的键值,则会立刻更新ImageView ,否则开启一个后台线程来加载这张图片。

[java]
1 2 3 4 5 6 7 8 9 public void loadBitmap(int resId, ImageView imageView) {
final String imageKey = String.valueOf(resId);
final Bitmap bitmap = getBitmapFromMemCache(imageKey);
if (bitmap != null ) {
imageView.setImageBitmap(bitmap);
} else {
imageView.setImageResource(R.drawable.image_placeholder);
BitmapWorkerTask task = new BitmapWorkerTask(imageView);
task.execute(resId);
10 11 }
}
BitmapWorkerTask 还要把新加载的图片的键值对放到缓存中。

[java]
1 2 3 4 5 6 7 8 9 10 class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> { // 在后台加载图片。

@Override
protected Bitmap doInBackground(Integer... params) {
final Bitmap bitmap = decodeSampledBitmapFromResource( getResources(), params[0], 100, 100);
addBitmapToMemoryCache(String.valueOf(params[0]), bitmap); return bitmap;
}
}
资料来源:北大青鸟上地软件园官网 /。

相关文档
最新文档