Android-Listview中Bitmap的缓存实现都有哪些方式

Web程序数据库 Web程序数据库 主题:1214 回复:2505

Android-Listview中Bitmap的缓存实现都有哪些方式

灵芸 发布于 2017-09-07 字数 495 浏览 1108 回复 9

我先列举一个吧:
1.使用最多的软引用
2.强引用(google建议使用的)

还有滚动的时候卡顿现象的处理:
处理方式是:
1.当listview滑动的时候,不进行远程下载任务
2.还有一种快的方式是,当取得图片的时候,每次不重新去下载(当没下载完成的时候),而是还是那个任务去下载。

。。。。。。。。

各位大侠,把你们的法宝都祭出来吧。。。。哈哈。 求学。。。
最好能有完整代码示例,或者说出大致思想。越细越好。 哈哈。

PS:
回答好,可加分。哈哈。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

支持 Markdown 语法,需要帮助?

评论(9

晚风撩人 2017-10-27 9 楼

弱弱问一句 浏览器不是自动下载缓存的么 你用IE chrome上淘宝 第二次都不需要重复加载啊

虐人心 2017-10-26 8 楼

1.我自己一般使用2中,一种是 通过 adapter 参数中的List的对应位置线放入一张加载中的图片,然后把adapter 赋值给View以后,开启另外一个线程下载图片,然后刷新adapter 达到效果,
2.自定意个adapter 然后在adapter 中获得获得图片路径有开启一个线程下载,之后在ImageView等VIEW 赋值。

瑾兮 2017-10-09 7 楼

这个我自己弄的图片缓存及异步下载工具类的,代码片段

/**

  • 图片异步加载
    */
    public class ImageLoaderUtil{

    /**
    • 从缓存文件中获取图片

    • @param context

    • @param imageUrl

    • @param imageCallback 不同地方使用到图片,传入不同的回调引用
      */
      public static void loadBitmapFormCacheFile(final Context context, final String imageUrl, final ImageCallback imageCallback) {
      final AhcouponApplication application = (AhcouponApplication) AhcouponApplication.getInstance();
      Bitmap bitmap = application.getmImageCache().get(imageUrl);

           //若是需要从缓存目录中读取图片,则调用此handler

      final Handler cacheHandler = new Handler() {
      public void handleMessage(Message message) {
      if(imageCallBackCache.hasImageCallBack(imageUrl)){
      //执行回调
      Iterator<ImageCallback> iterator = imageCallBackCache.getImageCallBack(imageUrl).iterator();
      while(iterator.hasNext()){
      ((ImageCallback)iterator.next()).imageLoaded((Bitmap) message.obj, imageUrl);
      }
      //清空
      imageCallBackCache.clearImageCallBack(imageUrl);
      }
      }
      };

      //若是直接能从缓存中获取图片,则直接调用此handler
      final Handler handler = new Handler() {
      public void handleMessage(Message message) {
      imageCallback.imageLoaded((Bitmap) message.obj, imageUrl);
      }
      };

      if (bitmap != null) {
      Message message = handler.obtainMessage(0, bitmap);
      handler.sendMessage(message);
      }else{

       //若图片回调集合不存在, 则从数据库或者网络取得; 若存在回调集合, 则加入等待队列
       if(imageCallBackCache.hasImageCallBack(imageUrl)){
           imageCallBackCache.putImageCallBack(imageUrl, imageCallback);
       }else{
           imageCallBackCache.putImageCallBack(imageUrl, imageCallback);
      
           new Thread() {
               @Override
               public void run() {
                                   //loadImageFromCacheFile这个方法,就是将图片从缓存目录中读取,若缓存中不存在图片,则通过imageUrl,进行网络下载
                   Bitmap loadedBitmap = loadImageFromCacheFile(context, imageUrl);
                   application.getmImageCache().put(imageUrl, loadedBitmap);
                   Message message = handler.obtainMessage(0, loadedBitmap);
                   cacheHandler.sendMessage(message);
               }
           }.start();
       }

      }

    }

    /**

    • 缓存类, key是图片标识(一般是图片的完整路径,防止同一张图片重复下载),

    • value: HashSet<ImageCallBack> , value设计成HashSet,若同一张图片多个地点同时需要展示,且又无缓存; 则无需重复下载图片,获取回调引用即可;且用HashSet为了防止ImageCallBack引用出现重复的情况
      */
      private static class ImageCallBackCache {

      //所有需要回调的图片监听缓存
      private WeakHashMap<String, HashSet<ImageCallback>> imageCallBackMap = null;

      public ImageCallBackCache(){
      imageCallBackMap = new WeakHashMap<String, HashSet<ImageCallback>>();
      }

      /**

      • 新增图片回调的监听
      • @param key
      • @param imageCallBack
        */
        public void putImageCallBack(String key, ImageCallback imageCallBack){
        getImageCallBack(key).add(imageCallBack);
        }

      /**

      • 获取图片的回调的监听集合
      • @param key
      • @return
        */
        public HashSet<ImageCallback> getImageCallBack(String key){
        if(imageCallBackMap.get(key) == null){
        imageCallBackMap.put(key, new HashSet<ImageCallback>());
        }
        return imageCallBackMap.get(key);
        }

      /**

      • 是否存在监听集合
      • @param key
      • @return
        */
        public boolean hasImageCallBack(String key){
        if(imageCallBackMap.get(key) == null){
        return false;
        }else{
        return true;
        }
        }

      /**

      • 清空图片回调集合
      • @param key
        */
        public void clearImageCallBack(String key){
        HashSet<ImageCallback> value = imageCallBackMap.get(key);
        value = null;
        imageCallBackMap.put(key, value);
        }
        }

    public interface ImageCallback {
    public void imageLoaded(Bitmap imageBitmap, String imageUrl);
    }

}

/**

  • 图片缓存

  • String就是imageUrl Bitmap就是缓存了
    */
    public class ImageCache extends WeakHashMap<String,Bitmap>{

    static String TAG ="ImageCache" ;
    private static final long serialVersionUID = 1L;

    //判断是是否缓存
    //weakhashMap自动释放未使用的value,但是key还存在,所有
    //containsKey(url) 和 get(url)!=null 都是必要的
    public boolean isCached(String url){

     boolean result =  (containsKey(url) &amp;&amp; get(url) != null);
     //Log.v(TAG , "ImageCache.size="+size()+";"+result );
     return result ;

    }
    }

若有不足之处,请见谅。

想挽留 2017-10-02 6 楼

大部分都是采用异步下载加缓存的方式,包括缓存到内存和缓存到本地。
这个貌似网上有这样的一个工具文件类,给你个地址
http://zheyiw.iteye.com/blog/1560125

灵芸 2017-10-01 5 楼

使用ViewHolder+异步下载图片。
使用ViewHolder的好处就是不管你的listview的count是多少,实际生成的item就只有那么几个,所以可以很好的解决卡顿现象。至于ViewHolder的例子,网上很多,搜一下吧。
异步下载,我的做饭是写在一个工具类里面,把下载到的图片全部存放到一个目录下,再用图片的路径和url对应,建立数据库,每次获取的图片的时候,先去数据库里面看有没有,如果有,检查文件是否已经被删除,然后再决定是不是需要重新下载。
大概思路就是这样。

想挽留 2017-09-25 4 楼

你应该不介意先看下这篇文章把,翻译自Google官网的。
[【Android Advanced Training - 09】高效地显示Bitmap图片 Lesson 3 - 两种缓存Bitmap的方式

其实我自己也有写一个内存缓存的Demo。
典型的ListView异步加载图片的例子,当然其中也使用了缓存的机制【写的比较复杂,考虑了并发等,不过我觉得值得学习】
源码我放在Github上,你可以看一看,点击这里
请多指教!

瑾兮 2017-09-18 3 楼

异步加载多的时候也挺郁闷,最好把所有的异步图片加载也放到一个队列里

甜柠檬 2017-09-10 2 楼

 package zhixin.android;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;

/**

  • @author 智欣仙子

  • */
    public class FocusAdapter extends BaseAdapter {
    private Context context;
    private List<Map<String,String>> list;
    public FocusAdapter(Context context){
    this.context=context;
    this.list=new ArrayList<Map<String,String>>();
    }
    public int getCount() {
    return list.size();
    }

    public Map<String,String> getItem(int position) {
    return list.get(position);
    }

    public long getItemId(int position) {
    return position;
    }
    public void addObject(Map<String,String> map){
    list.add(map);
    notifyDataSetChanged();
    }
    public View getView(int position, View convertView, ViewGroup parent) {
    View view = LayoutInflater.from(context).inflate(R.layout.focusgallery,null);
    ImageView image = (ImageView)view.findViewById(R.id.focusgallery_img);

     Map&lt;String,String&gt; map = list.get(position);
     image.setBackgroundDrawable(Drawable.createFromPath(map.get("source")));
     return view;

    }
    }

清晨说ぺ晚安 2017-09-07 1 楼

很多应用都有类似的功能,具体的细节没有仔细看过他们反编译的源码
正好最近在给公司写的一个项目中也用到了类似的功能,就说说我的实现吧

listview 需要的 list 里面应该保存有 image 的 url
list 的长度也是已知的,就算是再额外加载未显示的数据,每次增加的数量也是已知的
根据 1 和 2,创建一个 boolean 类型的数组记录当前已经获取到的 image 索引
开一个线程,循环获取所有需要的 image,每隔一定数量就通知一次界面要求 adapter notifyDataSetChanged() 一下
于此同时,listview 中的 image 位置事先填充一个灰色的默认图像,待 notifyDataSetChanged 时,再根据 步骤3 中的 boolean 数组的索引和值来加载 list 中指定的 image 即可
最后别忘了下载图像的线程结束后判断一下,是否还需要对最后一批加载的图像进行一次 notifyDataSetChanged 操作。

代码也没啥好贴的,下载的时候 BitmapFactory.decodeStream() 直接读文件流即可,有了 Bitmap 至于是放内存了缓存,还是放 Flash 里面保留都是你说了算的事情了;想做的更人性化,就加个 MD5 存起来(存哪都行,纯文本也行,xml也罢,数据库也可),只要 MD5 一样就不再需要下载直接读缓存即可。

斑驳敬上