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();
		}
	}                


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM