LruCache和DiskLruCache与BitmapFun之间的理解

        作为一名Android开发人员,相信大家对图片OOM的问题已经耳熟能详了,其中防止多图OOM的核心解决思路就是使用图片的3级缓存,那么就有几个疑问了,


1、图片3级缓存是哪几个?

      它们分别是内存、外存、网络。图片的读取首先从内存读取,如果找到就返回一个bitmap,否则到外存读取,如果外存还没有,最后才到网络上去读取。


2、3级缓存技术在android总如何体现和使用?

     内存缓存使用LruCache,我们知道,一个app一般分配16M或24M的内存,如果加载的图片很大很多,很容易超过容量上限导致oom,所以我们一般分配固定的内存给图片内存缓存用,具体介绍和使用可以参考

      http://blog.csdn.net/guolin_blog/article/details/9526203

LruCache只是管理了内存中图片的存储与释放,如果容量超过上限会把自动把最近最少使用的图片从缓存中移除。如果图片从内存中被移除的话,那么异步开启线程从网络上读取。

  privat LruCache<String, Bitmap> mMemoryCache;//这个是初始化LruCache的方法

        int maxMemory = (int) Runtime.getRuntime().maxMemory(); / 获取应用程序最大可用内存

        int cacheSize = maxMemory / 8;   // 设置图片缓存大小为程序最大可用内存的1/8         

            
        mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {  
            @Override  
            protected int sizeOf(String key, Bitmap bitmap) {  
                return bitmap.getByteCount();  //返回图片的字节数组大小
            }  
        };

 
这个类有2个核心方法 

 public void addBitmapToMemoryCache(String key, Bitmap bitmap) {  //将一张图片存入LruCache中
        if (getBitmapFromMemoryCache(key) == null) {              //key为图片网络url地址
            mMemoryCache.put(key, bitmap);                         //value为图片的bitmap对象
        }  
    }  

public Bitmap getBitmapFromMemoryCache(String key) {     从LruCache中获取一张图片,如果不存在就返回nul
        return mMemoryCache.get(key);                        //返回的是一个bitmap对象
    }  



     

             一个内存缓存对加速访问最近浏览过的Bitmap非常有帮助,但是你不能局限于内存中的可用图片。GridView这样有着更大的数据集的组件可以很轻易消耗掉内存缓存。你的应用有可能在执行其他任务(如打电话)的时候被打断,并且在后台的任务有可能被杀死或者缓存被释放。一旦用户重新聚焦(resume)到你的应用,你得再次处理每一张图片。所以在这种情况下,硬盘缓存可以用来存储Bitmap并在图片被内存缓存释放后减小图片加载的时间(次数)。当然,从硬盘加载图片比内存要慢,并且应该在后台线程进行,因为硬盘读取的时间是不可预知的。所以这个时候外存缓存使用DiskLruCache

DiskLruCache mDiskLruCache = null;         //DiskLruCache的初始化
try {  
    File cacheDir = getDiskCacheDir(context, "bitmap");  
    if (!cacheDir.exists()) {  
        cacheDir.mkdirs();  
    }  
    mDiskLruCache = DiskLruCache.open(cacheDir, getAppVersion(context), 1, 10 * 1024 * 1024);  
} catch (IOException e) {              //cacheDir是外存缓存的地址      最后的参数是缓存大小为10MB
    e.printStackTrace();  
} 



关于这个的介绍可以参考

http://blog.csdn.net/guolin_blog/article/details/28863651

图片在从网络上获取到之后都会存入到本地缓存中,因此即使手机在没有网络的情况下依然能够加载出以前浏览过图片。



   补充:

       由于DiskLruCache并不是由Google官方编写的,所以这个类并没有被包含在Android API当中,我们需要将这个类从网上下载下来,然后手动添加到项目当中。

        但是,一个优秀的程序必然会将内存缓存和硬盘缓存结合到一起使用,如何才能将LruCache和DiskLruCache完美结合到一起,具体参考http://blog.csdn.net/guolin_blog/article/details/34093441


        另外,网络读取使用HttpClient,可以参考我的上篇文章


3、BitmapFun是一个谷歌的开源异步读取图片的框架,使用了3级图片缓存技术BitmapFun中在下载后将Bitmap缓存起来,缓存做了两份:LruCacheDiskLruCache,分别是内存缓存硬盘缓存,BitmapFun使用的LruCache是它将最近被引用到的对象存储在一个强引用的LinkedHashMap中,并且在缓存超过了指定大小之后将最近不常使用的对象释放掉但是Memory Cache的Size是受限的,因此加入DiskLruCache,虽然在访问速度上逊于Memory Cache,但是速度也是相当可观的。也就是说它自己里面已经封装了LruCache和DiskLruCache和网络异步读取的所有操作,我们只用简单调用loadImage(图片url地址,image控件)方法即可,


所以总结bitmapFun的加载图片流程为

     ① UI:请求数据,使用唯一的Key值索引Memory Cache中的Bitmap。

     内存缓存:缓存搜索,如果能找到Key值对应的Bitmap,则返回数据。否则执行第三步。

     硬盘存储:使用唯一Key值对应的文件名,检索SDCard上的文件。

     如果有对应文件,使用BitmapFactory.decode*方法,解码Bitmap并返回数据,同时将数据写入缓存。如果没有对应文件,执行第五步。

     下载图片:启动异步线程,从数据源下载数据(Web)。

    ⑥ 若下载成功,将数据同时写入硬盘和缓存,并将Bitmap显示在UI中。

源码分析参考

http://blog.csdn.net/yuanzeyao/article/details/38355719


注意的是,BitmapFun这样子结合了memory和disk缓存和异步线程,是可以很大程度减少内存开销。但是还是有必要根据图片的大小做图片的压缩。

这里就需要使用BItmapFactory.option里面的inSampleSize来进行图片的压缩了。




=========================我是分割线==================================




接下来我们看一个具体例子:使用了BItMapFun 和GridView 展示图片,之前要记得导入BitMapFun的jar包

1、Image这个类放入一个图片的字符串数组,方便使用

public class Image {
	public final static String[] imageThumbUrls = new String[] {  
        "https://img-my.csdn.net/uploads/201407/26/1406383299_1976.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383291_6518.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383291_8239.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383290_9329.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383290_1042.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383275_3977.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383265_8550.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383264_3954.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383264_4787.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383264_8243.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383248_3693.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383243_5120.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383242_3127.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383242_9576.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383242_1721.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383219_5806.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383214_7794.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383213_4418.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383213_3557.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383210_8779.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383172_4577.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383166_3407.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383166_2224.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383166_7301.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383165_7197.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383150_8410.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383131_3736.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383130_5094.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383130_7393.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383129_8813.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383100_3554.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383093_7894.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383092_2432.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383092_3071.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383091_3119.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383059_6589.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383059_8814.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383059_2237.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383058_4330.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406383038_3602.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382942_3079.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382942_8125.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382942_4881.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382941_4559.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382941_3845.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382924_8955.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382923_2141.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382923_8437.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382922_6166.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382922_4843.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382905_5804.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382904_3362.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382904_2312.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382904_4960.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382900_2418.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382881_4490.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382881_5935.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382880_3865.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382880_4662.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382879_2553.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382862_5375.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382862_1748.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382861_7618.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382861_8606.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382861_8949.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382841_9821.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382840_6603.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382840_2405.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382840_6354.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382839_5779.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382810_7578.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382810_2436.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382809_3883.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382809_6269.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382808_4179.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382790_8326.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382789_7174.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382789_5170.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382789_4118.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382788_9532.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382767_3184.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382767_4772.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382766_4924.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382766_5762.jpg",  
        "https://img-my.csdn.net/uploads/201407/26/1406382765_7341.jpg"  
    };  
}

2、MainActivity里的具体代码

//使用了gridview和BitMapFun去网络上下载图片
public class MainActivity extends Activity {

	private GridView gridViewp;
	private ImageView imageView;
	private String[] data = Image.imageThumbUrls;
	private String url;
	private ImageFetcher fetcher;

	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		fetcher = new ImageFetcher(getApplicationContext(), 980, 980);
		fetcher.setExitTasksEarly(false);// 打开后台线程
		fetcher.setImageCache(new ImageCache(getApplicationContext(), "hemiy"));// 设置图片的磁盘缓存空间

		gridViewp = (GridView) findViewById(R.id.photo_wall);

		gridViewp.setAdapter(new BaseAdapter() {

			class ViewHolder {
				public ImageView image;
			}

			@Override
			public View getView(int position, View convertView, ViewGroup parent) {
				url = (String) getItem(position);
				ViewHolder holder = null;
				if (convertView == null) {
					holder = new ViewHolder();
					convertView = View.inflate(getApplicationContext(),
							R.layout.photo_item, null);
					holder.image = (ImageView) convertView
							.findViewById(R.id.photo);
					convertView.setTag(holder);
				} else {
					holder = (ViewHolder) convertView.getTag();
				}

				fetcher.loadImage(url, holder.image);

				return convertView;
			}

			@Override
			public long getItemId(int position) {
				// TODO Auto-generated method stub
				return position;
			}

			@Override
			public Object getItem(int position) {
				// TODO Auto-generated method stub
				return data[position];
			}

			@Override
			public int getCount() {
				// TODO Auto-generated method stub
				return data.length;
			}
		});

		gridViewp.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				Toast.makeText(getApplicationContext(),
						//这里的++position是正确指示点击的个数
						"你点击的是第" + (++position)+ "个", 1).show();

			}
		});
		

	}

	public void clearCache(View v){
		//无论怎样,外存里面的http文件夹下一定会有文件,但是里面图片大。我们自己设置的cache图片小
		DiskLruCache.clearCache(getApplicationContext(), "http");
		DiskLruCache.clearCache(getApplicationContext(), "hemiy");
	}
	@Override
	protected void onStop() {
		super.onStop();
		fetcher.setExitTasksEarly(true); // 关闭后台线程
	}
}


3、MainActivity里面的xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <!--
android:numColumns="auto_fit" ,GridView的列数设置为自动
android:columnWidth="90dp",每列的宽度,也就是Item的宽度
android:stretchMode="columnWidth",缩放与列宽大小同步
android:verticalSpacing="10dp",两行之间的边距,如:行一(NO.0~NO.2)与行二(NO.3~NO.5)间距为10dp
android:horizontalSpacing="10dp",两列之间的边距。
    -->
<!-- 以下的例子是完全按照郭林的范例
   android:columnWidth="100dp" 实际控制图片的大小
       在宽度不一样大小的屏幕上,列数会不一样
 -->
    <GridView
        android:id="@+id/photo_wall"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:gravity="center"
        android:columnWidth="100dp"
        android:stretchMode="columnWidth"
        android:numColumns="auto_fit"
        android:horizontalSpacing="1dp"
        android:verticalSpacing="1dp" >
    </GridView>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="clearCache"
        android:text="清除缓存" />

</LinearLayout></span>

photo_item的xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <ImageView
        android:id="@+id/photo"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"
        android:scaleType="fitXY"
        android:src="@drawable/ic_launcher" />

</LinearLayout>

4、最后记得在注册文件中,写上权限

 <!-- 联网 -->
    <uses-permission android:name="android.permission.INTERNET" />

    <!-- 外存储卡 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />

    <!-- 访问网络状态 -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />


完成了,可以在手机和平板上测试,手机上显示3个列表,而平板显示多个列表,但是每个列表的宽度是一样的。因为在GridView里面设置了

 android:columnWidth="100dp"



LRU Cache (最近最少使用缓存) 和 DiskLruCache (基于磁盘的 LRU 缓存) 是两种常见的缓存技术,它们的使用场景和优点如下: 1. LRU Cache 的使用场景: - 当需要缓存一些数据时,但是又不能无限制地增加内存消耗时,可以使用 LRU Cache 进行缓存。 - 当需要快速访问某些数据时,而这些数据的访问频率比较高时,可以使用 LRU Cache 进行缓存。 - 当需要保证缓存数据的时效性,避免过期数据对程序造成影响时,可以使用 LRU Cache 进行缓存。 2. DiskLruCache 的使用场景: - 当需要缓存一些大量的数据时,但是这些数据又不能全部存放在内存中时,可以使用 DiskLruCache 进行缓存。 - 当需要保证数据能够持久化存储时,可以使用 DiskLruCache 进行缓存。 - 当需要对缓存数据进行一些额外的操作时,例如压缩、加密等操作时,可以使用 DiskLruCache 进行缓存。 以下是使用 Kotlin 代码展示 LRU CacheDiskLruCache 的实现方法: ```kotlin // LRU Cache 的实现 import android.util.LruCache // 初始化一个 LRU Cache,设置最大缓存数量为 10 个 val lruCache = LruCache<String, String>(10) // 将数据加入缓存lruCache.put("key1", "value1") // 获取缓存中的数据 val value = lruCache.get("key1") // 移除缓存中的数据 lruCache.remove("key1") // 清除缓存中的所有数据 lruCache.evictAll() ``` ```kotlin // DiskLruCache 的实现 import com.jakewharton.disklrucache.DiskLruCache import java.io.File // 初始化一个 DiskLruCache,设置缓存目录和最大缓存数量为 10 个 val directory = File(context.cacheDir, "disk_cache") val diskCacheSize = 10 * 1024 * 1024 // 10MB val diskLruCache = DiskLruCache.open(directory, 1, 1, diskCacheSize.toLong()) // 将数据加入缓存中 val editor = diskLruCache.edit("key1") editor?.newOutputStream(0)?.use { outputStream -> outputStream.write("value1".toByteArray()) } editor?.commit() // 获取缓存中的数据 val snapshot = diskLruCache.get("key1") val value = snapshot?.getInputStream(0)?.bufferedReader().use { reader -> reader?.readText() } // 移除缓存中的数据 diskLruCache.remove("key1") // 清除缓存中的所有数据 diskLruCache.delete() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值