Android之ListView优化(使用Lrucache,图片滑动时使用默认图片,停止时加载)

注意: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 LooperThread extends 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();
		}
	}                
posted on 2013-03-30 15:50  lee0oo0  阅读(3537)  评论(0编辑  收藏  举报