Android 图片库universal-image-loader(一)

来源:互联网 发布:建筑电气设计师知乎 编辑:程序博客网 时间:2024/05/23 18:41

自己写ImageLoader类实现listview双缓存(一级,二级)异步(AsyncTask相当于新线程)


异步(AsyncTask相当于新线程)  


双缓存

一级缓存LinkedHashMap(LRU(Least Recently Used)策略,即当内存使用不足时,把最近最少使用的数据从缓存中移除,保留使用最频繁的数据。)


LinkedHashMap实现一级缓存代码

构造方法 new LinkedHashMap(10, 0.75, true);

参数1:缓存的大小一般为10或是5。

参数2:加载因子 经验值为0.75。

参数3:true:按照最近访问量的高低排序,false:按照插入顺序排序。

private HashMap<String, Bitmap> mFirstLevelCache=new LinkedHashMap<String, Bitmap>(MAX_CAPACITY / 2, 0.75f, true) {

private static final long serialVersionUID=1L;

protected boolean removeEldestEntry(Entry<String, Bitmap> eldest) {

if(size()>MAX_CAPACITY){//当超过一级缓存阈值的时候,将老的值从一级缓存搬到二级缓存

mSecondLevelCache.put(eldest.getKey(),newSoftReference<Bitmap>(eldest.getValue()));

return true;

}

return false;

};

};


removeEldestEntry方法

如果size()>10(LinkedHashMap的长度大于10)返回true并将图片放到二级缓存,否则返回false即不清除缓存。

Protected boolean removeEldestEntry(java.util.Map.Entry<String,Bitmap> eldest) {

if(size()>10){

//一级缓存清空 放到二级缓存

return true;

}else{

return false;

}

};


二级缓存ConcurrentHashMap

private ConcurrentHashMap <String, SoftReference<Bitmap>> mSecondLevelCache=

new ConcurrentHashMap<String,SoftReference<Bitmap>>(5);

采用的是软应用,只有在内存吃紧的时候软应用才会被回收,有效的避免了oom。

一级缓存放入到二级缓存中时

m.put(eldest.getKey(),new SoftReference<Bitmap>(eldest.getValue()));


总结

设置两级缓存,第一级用LinkedHashMap<String,Bitmap>保留Bitmap的强引用,但是控制缓存的大小MAX_CAPACITY=10,当继续向该缓存中存数据的时候,将会把一级缓存中的最近最少使用的元素放入二级缓存ConcurrentHashMap<String, SoftReference<Bitmap>>,二级缓存中保留的Bitmap的软引用。 SoftReference:它保存的对象实例,除非JVM即将OutOfMemory,否则不会被GC回收。这个特性使得它特别适合设计对象Cache。对于Cache,我们希望被缓存的对象最好始终常驻内存,但是如果JVM内存吃紧,为了不发生OutOfMemoryError导致系统崩溃,必要的时候也允许JVM回收Cache的内存,待后续合适的时机再把数据重新Load到Cache中。这样可以系统设计得更具弹性。


使用步骤

在适配器中

if(!mBusy){

  loader.loadListImage(path,vh.pathiv,this);

}else{ vh.pathiv.setBackgroundResource(R.drawable.ic_launcher);

}


loadListImage方法(工具类)

public void loadListImage(String url, imageview, adapter) {

resetPurgeTimer();//重置缓存

Bitmap bitmap=getBitmapFromCache(url);// 从缓存中读取

if (bitmap == null) {

imageview.setImageResource();//缓存没有设为默认图片

ImageLoadTask imageLoadTask = new ImageLoadTask();

imageLoadTask.execute(url,adapter);

}else{

imageview.setImageBitmap(bitmap);//设为缓存图片

}

}



private void resetPurgeTimer() {

mPurgeHandler.removeCallbacks(mClearCache);

mPurgeHandler.postDelayed(mClearCache, DELAY_BEFORE_PURGE);

}



private Handler mPurgeHandler = new Handler();



private Runnable mClearCache = new Runnable() {

public void run() {

clear();

}

};



private void clear() {

mFirstLevelCache.clear();

mSecondLevelCache.clear();

}



public Bitmap getBitmapFromCache(String url) {

Bitmap bitmap = null;

bitmap = getFromFirstLevelCache(url);// 从一级缓存中拿

if (bitmap != null) {

return bitmap;

}

bitmap = getFromSecondLevelCache(url);// 从二级缓存中拿

return bitmap;

}



private Bitmap getFromFirstLevelCache(String url) {

Bitmap bitmap = null;

synchronized (mFirstLevelCache) {

bitmap = mFirstLevelCache.get(url);

if (bitmap != null) {// 将最近访问的元素放到链的头部,提高下一次访问该元素的检索速度(LRU算法)

mFirstLevelCache.remove(url);

mFirstLevelCache.put(url, bitmap);

}

}

return bitmap;

}



private Bitmap getFromSecondLevelCache(String url) {

Bitmap bitmap = null;

SoftReference<Bitmap> softReference = mSecondLevelCache.get(url);

f (softReference != null) {

bitmap = softReference.get();

if (bitmap == null) {// 由于内存吃紧,软引用已经被gc回收了

mSecondLevelCache.remove(url);

}

}

return bitmap;

}



class ImageListLoadTask extends AsyncTask<Object, Void, Bitmap> {

String url;

BaseAdapter adapter;

@Override

protected Bitmap doInBackground(Object... params) {

url=(String)params[0];

adapter=(BaseAdapter) params[1];

Bitmap bitmap=loadImageFromInternet(url);

return bitmap;

}

 

@Override

protected void onPostExecute(Bitmap result) {

if (result==null) {

return;

}

addImage2Cache(url, result);//放入缓存

adapter.notifyDataSetChanged();//触发getView方法执行 这个时候getView实际上会拿到刚刚缓存好的图片

}

}



public void addImage2Cache(String url, Bitmap value) {

if (value == null || url == null) {

return;

}

synchronized (mFirstLevelCache) {

mFirstLevelCache.put(url, value);

}

}



附1:LruCache类

LruCache是android提供的一个缓存工具类,其算法是最近最少使用算法。它把最近使用的对象用“强引用”存储在LinkedHashMap中,并且把最近最少使用的对象在缓存值达到预设定值之前就从内存中移除。

其中用到的数据对象是LinkedHashMap,所以不要把这个类想的多么深不可测,还是数据结构 + 算法。既然用到了这个map,自然就要有添加修改和删除操作了,用到了最近最少使用算法,自然就要用到优先级了。

作为缓存,肯定有一个缓存的大小,这个大小是可以设定的(自定义sizeOf())。当你访问了一个item(需要缓存的对象),这个item应该被加入到内存中,然后移动到一个队列的顶部,如此循环后这个队列的顶部应该是最近访问的item了,而队尾部就是很久没有访问的item,这样我们就应该对队尾部的item优先进行回收操作。

因为用到了HashMap,那么就有这个数据存储对象的特点(KEY-VALUE),放入这个map的item应该会被强引用,要回收这个对象的时候是让这个key为空,这样就让有向图找不到对应的value,最终被GC。

缓存的最大特点是不做重复的劳动,如果你之前已经缓存过这个item了,当你再次想要缓存这个item时,应该会先判断是否已经缓存好了,如果已经缓存,那么就不执行添加的操作。

我们应该能通过某个方法来清空缓存,这个缓存在app被退出后就自动清理,不会常驻内存。

sizeof()方法。这个方法默认返回的是你缓存的item数目,如果你想要自定义size的大小,直接重写这个方法,返回自定义的值即可。


附2:LinkedHashMap

LinkedHashMap 是HashMap的一个子类,保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.也可以在构造时用带参数,按照应用次数排序。在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会比 LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。



0 0