android使用LruCache对listview加载图片时候优化处理

注意:LruCache是有版本限制的,低版本的sdk需要在libs文件夹添加相应的support-4v文件。 本文改造的大部分是参考http://www.iteye.com/topic/1118828,感谢。 不废话直接上工程代码,内有关键注释,项目就不上传了,自己对照着上面网址改呗。

首先是Application文件,负责创建图片存储文件夹:

public class MyApp extends Application{
    @Override
    public void onCreate() {
        super.onCreate();
        File f = new File(Environment.getExternalStorageDirectory()+"/TestSyncListView/pic/");
        if (!f.exists()) {
            f.mkdirs();
        }
    }
}

图像读取工具类:

public class SyncImageLoaderUtil
 {
    private Object
 lock = new Object(); 
       
    private boolean mAllowLoad
 = true; 
   
    private boolean firstLoad
 = true; 
   
    private int mStartLoadLimit
 = 0; 
   
    private int mStopLoadLimit
 = 0; 
   
    final Handler
 handler = new Handler(); 
   
//   
 private HashMap<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>(); 
   
    private LruCache<String,Bitmap>
 mMemoryCache;
     
    RunInOtherThread
 runInOutherThread;  
   
    public SyncImageLoaderUtil(Context
 context) {  
        super(); 
         
        int memClass
 = ((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
        int cacheSize
 = 1024 *1024 *memClass
 / 8;
        mMemoryCache
 = new LruCache<String,
 Bitmap>(cacheSize){
            @Override
            protected int sizeOf(String
 key, Bitmap value) {
                //
 TODO Auto-generated method stub
                return value.getRowBytes();
            }
        };
         
        runInOutherThread
 = new RunInOtherThread(); 
        runInOutherThread.start(); 
    } 
   
    public interface OnImageLoadListener
 {  
        public void onImageLoad(Integer
 t, Drawable drawable);  
   
        public void onError(Integer
 t);  
    } 
   
    public void setLoadLimit(int startLoadLimit,int stopLoadLimit)
 {  
        if (startLoadLimit
 > stopLoadLimit) {  
//         
 LogUtil.i("test", startLoadLimit+"--错误---"+stopLoadLimit);
            return; 
        } 
        mStartLoadLimit
 = startLoadLimit;  
        mStopLoadLimit
 = stopLoadLimit;  
    } 
   
    public void restore()
 {  
        mAllowLoad
 = true; 
        firstLoad
 = true; 
    } 
   
    public void lock()
 {  
        mAllowLoad
 = false; 
        firstLoad
 = false; 
    } 
   
    public void unlock()
 {  
        mAllowLoad
 = true; 
        synchronized (lock)
 {  
            lock.notifyAll(); 
        } 
    } 
   
    public void loadImage(Integer
 t, String imageUrl,  
            OnImageLoadListener
 listener) {  
        final OnImageLoadListener
 mListener = listener;  
        final String
 mImageUrl = imageUrl;  
        final Integer
 mt = t;  
           
        runInOutherThread.getHandler().post(new Runnable()
 {  
   
            @Override 
            public void run()
 {  
                if (!mAllowLoad)
 {  
                    synchronized (lock)
 {  
                        try { 
                            lock.wait(); 
                        }catch (InterruptedException
 e) {  
                            //
 TODO Auto-generated catch block  
                            e.printStackTrace(); 
                        } 
                    } 
                } 
                   
                if (mAllowLoad
 && firstLoad) {  
                    loadImage(mImageUrl,
 mt, mListener);  
                } 
   
//               
 LogUtil.e("test", "原始开始:"+mStartLoadLimit+"原始当前位置:"+mt+"原始结束:"+mStopLoadLimit);
                if (mAllowLoad
 && mt <= mStopLoadLimit && mt >= mStartLoadLimit) {  
//                 
 LogUtil.e("test", "开始:"+mStartLoadLimit+"当前位置:"+mt+"结束:"+mStopLoadLimit);
                    loadImage(mImageUrl,
 mt, mListener);
                } 
            } 
   
        }); 
    } 
       
    private void loadImage(final String
 mImageUrl, final Integer
 mt,  
            final OnImageLoadListener
 mListener) {  
   
        if (mImageUrl!=null &&
 mMemoryCache.get(mImageUrl)!=null)
 {  
//           
 SoftReference<Drawable> softReference = imageCache.get(mImageUrl);  
            final Drawable
 d = new BitmapDrawable(mMemoryCache.get(mImageUrl)); 
//           
 LogUtil.d("ppp", "drawable:"+d);
            if (d
 != null)
 {  
                handler.post(new Runnable()
 {  
                    @Override 
                    public void run()
 {  
                        if (mAllowLoad)
 {  
                            mListener.onImageLoad(mt,
 d);  
                        } 
                    } 
                }); 
                return; 
            } 
        } 
        try { 
            final Drawable
 d = loadImageFromUrl(mImageUrl);  
            if (d
 != null)
 {  
                mMemoryCache.put(mImageUrl,
 ((BitmapDrawable)d).getBitmap());
            } 
            handler.post(new Runnable()
 {  
                @Override 
                public void run()
 {  
                    if (mAllowLoad)
 {  
                        mListener.onImageLoad(mt,
 d);  
                    } 
                } 
            }); 
        }catch (IOException
 e) {  
            handler.post(new Runnable()
 {  
                @Override 
                public void run()
 {  
                    mListener.onError(mt); 
                } 
            }); 
            e.printStackTrace(); 
        } 
    } 
   
    public static Drawable
 loadImageFromUrl(String url) throws IOException
 {  
        //DebugUtil.debug(url); 
        if (Environment.getExternalStorageState().equals( 
                Environment.MEDIA_MOUNTED))
 {  
            File
 f = new File(Environment.getExternalStorageDirectory() 
                    +"/Weiyu/pic/" +
 MD5Util.getMD5(url.getBytes()));  
            if (f.exists())
 {  
                FileInputStream
 fis = new FileInputStream(f); 
                Drawable
 d = Drawable.createFromStream(fis, "src"); 
                return d; 
            } 
            URL
 m = new URL(url); 
            InputStream
 i = (InputStream) m.getContent();  
            DataInputStream
 in = new DataInputStream(i); 
            FileOutputStream
 out = new FileOutputStream(f); 
            byte[]
 buffer = new byte[1024]; 
            int byteread
 = 0; 
            while ((byteread
 = in.read(buffer)) != -1)
 {  
                out.write(buffer,0,
 byteread);  
            } 
            
            in.close(); 
            out.close();
            return loadImageFromUrl(url); 
        }else { 
            URL
 m = new URL(url); 
            InputStream
 i = (InputStream) m.getContent();  
            Drawable
 d = Drawable.createFromStream(i, "src"); 
            return d; 
        } 
   
    } 
}

线程辅助类:

public class RunInOtherThread
 {
    private static final String
 LOG_TAG = "RunInOtherThread"; 
     
    private LooperThread
 localThread = new LooperThread(); 
       
    private boolean isRunning
 = true; 
   
    public Handler
 getHandler(){  
        return localThread.getHandler(); 
    } 
       
    private class LooperThreadextends Thread
 {  
        private Handler
 mHandler;  
   
        public void run()
 {  
            Looper.prepare(); 
            mHandler
 = new Handler()
 {  
                public void handleMessage(Message
 msg) {  
                    onReceiveMessage(msg.what); 
                } 
            }; 
            Looper.loop(); 
        } 
           
        Handler
 getHandler(){  
            return mHandler; 
        } 
      
    } 
       
    public void start(){ 
        localThread.start(); 
    } 
       
    public void quit(){ 
        localThread.getHandler().getLooper().quit(); 
    } 
       
    public void sendMessage(int what){ 
        getHandler().sendEmptyMessage(what); 
    } 
       
    public Thread
 getThread(){  
        return localThread; 
    } 
       
    public void onReceiveMessage(int what){};
}

使用类:

 //
 实例化工具类
SyncImageLoaderUtil
 syncImageLoader = new SyncImageLoaderUtil(mContext);
 
syncImageLoader.loadImage(position,
 model.mPic, imageLoadListener);//应用接口:参数一是加载图片的位置;参数二是加载的ImageView;参数三是回调接口
 
//
 map保存的键是位置,值是listview对应位置的布局
HashMap
 map = new HashMap();
map.put(position,
 convertView);
 
SyncImageLoaderUtil.OnImageLoadListener
 imageLoadListener = new SyncImageLoaderUtil.OnImageLoadListener()
 {
 
        @Override
        public void onImageLoad(Integer
 t, Drawable drawable) {
            View
 view = (View) map.get(t);
            if (view
 != null)
 {
                ImageView
 iv = (ImageView) view.findViewById(R.id.image);
                iv.setBackgroundDrawable(drawable);
            }
        }
 
        @Override
        public void onError(Integer
 t) {
                        //
 图片加载失败
                       //
 取得listview对应的位置的行的内容布局
                    MusicModel
 model = (MusicModel) getItem(t);
            View
 view = mListView.findViewWithTag(model);
            if (view
 != null)
 {
                ImageView
 iv = (ImageView) view.findViewById(R.id.image);
                iv.setBackgroundResource(R.drawable.img_pic);
            }
        }
 
    };
 
 
//
 实现类而且需要实现OnScrollListener接口
public void loadImage()
 {
                //
 不要在这里使用listview的getFirstVisiblePosition方法,位置不准
        if (end
 >= getCount()) {
            end
 = getCount() - 1;
        }
        syncImageLoader.setLoadLimit(start,
 end);
        syncImageLoader.unlock();
    }
 
    @Override
    public void onScrollStateChanged(AbsListView
 view, int scrollState)
 {
        //
 TODO Auto-generated method stub
        if (lodingView)
 {
            switch (scrollState)
 {
            case AbsListView.OnScrollListener.SCROLL_STATE_FLING:
                syncImageLoader.lock();
                break;
            case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:
 
                loadImage();
                break;
            case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
                syncImageLoader.lock();
                break;
            default:
                break;
            }
        }
    }
 
    @Override
    public void onScroll(AbsListView
 view, int firstVisibleItem,
            int visibleItemCount,int totalItemCount)
 {
        //
 在这里取得的位置较准确,不过也会出现特殊的奇疤机型是不行的
                //
 start与end是定义的变量
        start
 = firstVisibleItem;
        end
 = firstVisibleItem + visibleItemCount;
        if (firstVisibleItem
 != 0)
 {
                        //
 lodingView是控制变量,用来控制第一次进来视图加载读取图片
            lodingView
 = true;
        }else {
            lodingView
 = false;
            loadImage();
        }
    }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏郭耀华‘s Blog

android 一些常用的功能方法代码块

我们这些苦逼的程序员在工作中,每一个老板都希望我们都能把手头的工作做好的,而且是越快越好,那我们要怎么样才能快起来呢?对于开发中常用的代码块无限复做是我们工作...

2674
来自专栏后端之路

SpringBoot之条件注解

背景 之前写过关于Spring和Maven的profile的区别 maven profile VS spring profile 我们可以通过上述的profil...

3675
来自专栏码匠的流水账

聊聊springcloud的featuresEndpoint

spring-cloud-commons-2.0.0.RC1-sources.jar!/org/springframework/cloud/client/Com...

761
来自专栏肖蕾的博客

自定义BaseAdapter完美解决ListView异常:java.lang.IllegalStateException这是代码使用方法原理另外

1418
来自专栏Java与Android技术栈

用kotlin打造简化版本的ButterKnife

大名鼎鼎的 ButterKnife 库相信很多 android 开发者都听过,在 Github 上star的数目已经快15k了,而且很多知名的app都在使用。

1303
来自专栏向治洪

RecyclerView 实现横向滚动效果

我相信很久以前,大家在谈横向图片轮播是时候,优先会选择具有HorizontalScrollView效果和ViewPager来做,不过自从Google大会之后,系...

3956
来自专栏MyBlog

关于Valley网络框架

882
来自专栏编程之路

羊皮书APP(Android版)开发系列(十)Android开发常用工具类

1011
来自专栏技术小黑屋

关于获取当前Activity的一些思考

在Android开发过程中,我们有时候需要获取当前的Activity实例,比如弹出Dialog操作,必须要用到这个。关于如何实现由很多种思路,这其中有的简单,有...

1493
来自专栏Android知识点总结

O3-开源框架使用之Butterknife 8.8.1及源码浅析

cast()方法是Clazz的一个公共方法:由下可见它反会一个由传入值强转成的T类型对象

1864

扫码关注云+社区