您的位置:首页 > 其它

LruCache和DiskLruCache与BitmapFun之间的理解

2015-07-28 20:37 483 查看
作为一名Android开发人员,相信大家对图片OOM的问题已经耳熟能详了,其中防止多图OOM的核心解决思路就是使用图片的3级缓存,那么就有几个疑问了,1、图片3级缓存是哪几个?它们分别是内存、外存、网络。图片的读取首先从内存读取,如果找到就返回一个bitmap,否则到外存读取,如果外存还没有,最后才到网络上去读取。2、3级缓存技术在android总如何体现和使用?内存缓存使用LruCache,我们知道,一个app一般分配16M或24M的内存,如果加载的图片很大很多,很容易超过容量上限导致oom,所以我们一般分配固定的内存给图片内存缓存用,具体介绍和使用可以参考 /article/1562144.htmlLruCache只是管理了内存中图片的存储与释放,如果容量超过上限会把自动把最近最少使用的图片从缓存中移除。如果图片从内存中被移除的话,那么异步开启线程从网络上读取。
privat LruCache<String, Bitmap> mMemoryCache;//这个是初始化LruCache的方法
        int maxMemory = (int) Runtime.getRuntime().maxMemory(); / 获取应用程序最大可用内存int cacheSize = maxMemory / 8;   // 设置图片缓存大小为程序最大可用内存的1/8mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {@Overrideprotected 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中获取一张图片,如果不存在就返回nulreturn 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是外存缓存的地址      最后的参数是缓存大小为10MBe.printStackTrace();} 
关于这个的介绍可以参考/article/1562112.html图片在从网络上获取到之后都会存入到本地缓存中,因此即使手机在没有网络的情况下依然能够加载出以前浏览过图片。补充:由于DiskLruCache并不是由Google官方编写的,所以这个类并没有被包含在Android API当中,我们需要将这个类从网上下载下来,然后手动添加到项目当中。但是,一个优秀的程序必然会将内存缓存和硬盘缓存结合到一起使用,如何才能将LruCache和DiskLruCache完美结合到一起,具体参考/article/1562111.html另外,网络读取使用HttpClient,可以参考我的上篇文章3、BitmapFun是一个谷歌的开源异步读取图片的框架,使用了3级图片缓存技术,BitmapFun中在下载后将Bitmap缓存起来,缓存做了两份:LruCache和DiskLruCache,分别是内存缓存和硬盘缓存,BitmapFun使用的LruCache是将它将最近被引用到的对象存储在一个强引用的LinkedHashMap中,并且在缓存超过了指定大小之后将最近不常使用的对象释放掉。但是MemoryCache的Size是受限的,因此加入DiskLruCache,虽然在访问速度上逊于Memory Cache,但是速度也是相当可观的。也就是说它自己里面已经封装了LruCache和DiskLruCache和网络异步读取的所有操作,我们只用简单调用loadImage(图片url地址,image控件)方法即可,所以总结bitmapFun的加载图片流程为① UI:请求数据,使用唯一的Key值索引MemoryCache中的Bitmap。② 内存缓存:缓存搜索,如果能找到Key值对应的Bitmap,则返回数据。否则执行第三步。③ 硬盘存储:使用唯一Key值对应的文件名,检索SDCard上的文件。④ 如果有对应文件,使用BitmapFactory.decode*方法,解码Bitmap并返回数据,同时将数据写入缓存。如果没有对应文件,执行第五步。⑤ 下载图片:启动异步线程,从数据源下载数据(Web)。⑥ 若下载成功,将数据同时写入硬盘和缓存,并将Bitmap显示在UI中。源码分析参考/article/1503559.html注意的是,BitmapFun这样子结合了memory和disk缓存和异步线程,是可以很大程度减少内存开销。但是还是有必要根据图片的大小做图片的压缩。这里就需要使用BItmapFactory.option里面的inSampleSize来进行图片的压缩了。=========================我是分割线==================================接下来我们看一个具体例子:使用了BItMapFun 和GridView 展示图片,之前要记得导入BitMapFun的jar包1、Image这个类放入一个图片的字符串数组,方便使用
public class Image {public final static String[] imageThumbUrls = new String[] {"http://img.my.csdn.net/uploads/201407/26/1406383299_1976.jpg","http://img.my.csdn.net/uploads/201407/26/1406383291_6518.jpg","http://img.my.csdn.net/uploads/201407/26/1406383291_8239.jpg","http://img.my.csdn.net/uploads/201407/26/1406383290_9329.jpg","http://img.my.csdn.net/uploads/201407/26/1406383290_1042.jpg","http://img.my.csdn.net/uploads/201407/26/1406383275_3977.jpg","http://img.my.csdn.net/uploads/201407/26/1406383265_8550.jpg","http://img.my.csdn.net/uploads/201407/26/1406383264_3954.jpg","http://img.my.csdn.net/uploads/201407/26/1406383264_4787.jpg","http://img.my.csdn.net/uploads/201407/26/1406383264_8243.jpg","http://img.my.csdn.net/uploads/201407/26/1406383248_3693.jpg","http://img.my.csdn.net/uploads/201407/26/1406383243_5120.jpg","http://img.my.csdn.net/uploads/201407/26/1406383242_3127.jpg","http://img.my.csdn.net/uploads/201407/26/1406383242_9576.jpg","http://img.my.csdn.net/uploads/201407/26/1406383242_1721.jpg","http://img.my.csdn.net/uploads/201407/26/1406383219_5806.jpg","http://img.my.csdn.net/uploads/201407/26/1406383214_7794.jpg","http://img.my.csdn.net/uploads/201407/26/1406383213_4418.jpg","http://img.my.csdn.net/uploads/201407/26/1406383213_3557.jpg","http://img.my.csdn.net/uploads/201407/26/1406383210_8779.jpg","http://img.my.csdn.net/uploads/201407/26/1406383172_4577.jpg","http://img.my.csdn.net/uploads/201407/26/1406383166_3407.jpg","http://img.my.csdn.net/uploads/201407/26/1406383166_2224.jpg","http://img.my.csdn.net/uploads/201407/26/1406383166_7301.jpg","http://img.my.csdn.net/uploads/201407/26/1406383165_7197.jpg","http://img.my.csdn.net/uploads/201407/26/1406383150_8410.jpg","http://img.my.csdn.net/uploads/201407/26/1406383131_3736.jpg","http://img.my.csdn.net/uploads/201407/26/1406383130_5094.jpg","http://img.my.csdn.net/uploads/201407/26/1406383130_7393.jpg","http://img.my.csdn.net/uploads/201407/26/1406383129_8813.jpg","http://img.my.csdn.net/uploads/201407/26/1406383100_3554.jpg","http://img.my.csdn.net/uploads/201407/26/1406383093_7894.jpg","http://img.my.csdn.net/uploads/201407/26/1406383092_2432.jpg","http://img.my.csdn.net/uploads/201407/26/1406383092_3071.jpg","http://img.my.csdn.net/uploads/201407/26/1406383091_3119.jpg","http://img.my.csdn.net/uploads/201407/26/1406383059_6589.jpg","http://img.my.csdn.net/uploads/201407/26/1406383059_8814.jpg","http://img.my.csdn.net/uploads/201407/26/1406383059_2237.jpg","http://img.my.csdn.net/uploads/201407/26/1406383058_4330.jpg","http://img.my.csdn.net/uploads/201407/26/1406383038_3602.jpg","http://img.my.csdn.net/uploads/201407/26/1406382942_3079.jpg","http://img.my.csdn.net/uploads/201407/26/1406382942_8125.jpg","http://img.my.csdn.net/uploads/201407/26/1406382942_4881.jpg","http://img.my.csdn.net/uploads/201407/26/1406382941_4559.jpg","http://img.my.csdn.net/uploads/201407/26/1406382941_3845.jpg","http://img.my.csdn.net/uploads/201407/26/1406382924_8955.jpg","http://img.my.csdn.net/uploads/201407/26/1406382923_2141.jpg","http://img.my.csdn.net/uploads/201407/26/1406382923_8437.jpg","http://img.my.csdn.net/uploads/201407/26/1406382922_6166.jpg","http://img.my.csdn.net/uploads/201407/26/1406382922_4843.jpg","http://img.my.csdn.net/uploads/201407/26/1406382905_5804.jpg","http://img.my.csdn.net/uploads/201407/26/1406382904_3362.jpg","http://img.my.csdn.net/uploads/201407/26/1406382904_2312.jpg","http://img.my.csdn.net/uploads/201407/26/1406382904_4960.jpg","http://img.my.csdn.net/uploads/201407/26/1406382900_2418.jpg","http://img.my.csdn.net/uploads/201407/26/1406382881_4490.jpg","http://img.my.csdn.net/uploads/201407/26/1406382881_5935.jpg","http://img.my.csdn.net/uploads/201407/26/1406382880_3865.jpg","http://img.my.csdn.net/uploads/201407/26/1406382880_4662.jpg","http://img.my.csdn.net/uploads/201407/26/1406382879_2553.jpg","http://img.my.csdn.net/uploads/201407/26/1406382862_5375.jpg","http://img.my.csdn.net/uploads/201407/26/1406382862_1748.jpg","http://img.my.csdn.net/uploads/201407/26/1406382861_7618.jpg","http://img.my.csdn.net/uploads/201407/26/1406382861_8606.jpg","http://img.my.csdn.net/uploads/201407/26/1406382861_8949.jpg","http://img.my.csdn.net/uploads/201407/26/1406382841_9821.jpg","http://img.my.csdn.net/uploads/201407/26/1406382840_6603.jpg","http://img.my.csdn.net/uploads/201407/26/1406382840_2405.jpg","http://img.my.csdn.net/uploads/201407/26/1406382840_6354.jpg","http://img.my.csdn.net/uploads/201407/26/1406382839_5779.jpg","http://img.my.csdn.net/uploads/201407/26/1406382810_7578.jpg","http://img.my.csdn.net/uploads/201407/26/1406382810_2436.jpg","http://img.my.csdn.net/uploads/201407/26/1406382809_3883.jpg","http://img.my.csdn.net/uploads/201407/26/1406382809_6269.jpg","http://img.my.csdn.net/uploads/201407/26/1406382808_4179.jpg","http://img.my.csdn.net/uploads/201407/26/1406382790_8326.jpg","http://img.my.csdn.net/uploads/201407/26/1406382789_7174.jpg","http://img.my.csdn.net/uploads/201407/26/1406382789_5170.jpg","http://img.my.csdn.net/uploads/201407/26/1406382789_4118.jpg","http://img.my.csdn.net/uploads/201407/26/1406382788_9532.jpg","http://img.my.csdn.net/uploads/201407/26/1406382767_3184.jpg","http://img.my.csdn.net/uploads/201407/26/1406382767_4772.jpg","http://img.my.csdn.net/uploads/201407/26/1406382766_4924.jpg","http://img.my.csdn.net/uploads/201407/26/1406382766_5762.jpg","http://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;}@Overridepublic 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;}@Overridepublic long getItemId(int position) {// TODO Auto-generated method stubreturn position;}@Overridepublic Object getItem(int position) {// TODO Auto-generated method stubreturn data[position];}@Overridepublic int getCount() {// TODO Auto-generated method stubreturn data.length;}});gridViewp.setOnItemClickListener(new OnItemClickListener() {@Overridepublic 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");}@Overrideprotected 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)间距为10dpandroid:horizontalSpacing="10dp",两列之间的边距。--><!-- 以下的例子是完全按照郭林的范例android:columnWidth="100dp" 实际控制图片的大小在宽度不一样大小的屏幕上,列数会不一样--><GridViewandroid: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><Buttonandroid: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" ><ImageViewandroid: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"
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: