MainActivity如下:
package cc.testlrucache;import android.os.Bundle;import android.widget.GridView;import android.app.Activity;/** * Demo描述: * Android利用LruCache為GridView載入大量本地圖片完整樣本,防止OOM * * 更多參考: * http://blog.csdn.net/lfdfhl */public class MainActivity extends Activity {private GridView mGridView;private GridViewAdapter mGridViewAdapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);init();}private void init(){mGridView = (GridView) findViewById(R.id.gridView);mGridViewAdapter = new GridViewAdapter(this, 0, ImagesPath.IMAGES_PATH, mGridView);mGridView.setAdapter(mGridViewAdapter);}}
GridViewAdapter如下:
package cc.testlrucache;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.support.v4.util.LruCache;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.AbsListView;import android.widget.ArrayAdapter;import android.widget.GridView;import android.widget.ImageView;import android.widget.AbsListView.OnScrollListener;/** * LruCache的流程分析: * * 從第一次進入應用的情況下開始 * 1 依據圖片的Path從LruCache緩衝中取圖片. * 若圖片存在緩衝中,則顯示該圖片;否則顯示預設圖片 * 2 因為是第一次進入該介面所以會執行: * loadBitmaps(firstVisibleItem, visibleItemCount); * * 從loadBitmaps()方法作為切入點,繼續往下梳理 * * 3 嘗試從LruCache緩衝中取圖片.如果在顯示即可,否則進入4 * 4 從SDCrad讀取圖片,並且將讀取後的圖片儲存到LruCache緩衝中 * * 5 在停止滑動時,會調用loadBitmaps(firstVisibleItem, visibleItemCount) * 顯示目前GridView可見Item的圖片 */public class GridViewAdapter extends ArrayAdapter {private GridView mGridView;//圖片緩衝類private LruCache mLruCache;//GridView中可見的第一張圖片的下標private int mFirstVisibleItem;//GridView中可見的圖片的數量private int mVisibleItemCount;//記錄是否是第一次進入該介面private boolean isFirstEnterThisActivity = true;public GridViewAdapter(Context context, int textViewResourceId,String[] objects, GridView gridView) {super(context, textViewResourceId, objects);mGridView = gridView;mGridView.setOnScrollListener(new ScrollListenerImpl());//應用程式最大可用記憶體int maxMemory = (int) Runtime.getRuntime().maxMemory();//設定圖片緩衝大小為maxMemory的1/3int cacheSize = maxMemory/3;mLruCache = new LruCache(cacheSize) {@Overrideprotected int sizeOf(String key, Bitmap bitmap) {return bitmap.getRowBytes() * bitmap.getHeight();}};}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {String path = getItem(position);View view;if (convertView == null) {view = LayoutInflater.from(getContext()).inflate(R.layout.gridview_item, null);} else {view = convertView;}ImageView imageView = (ImageView) view.findViewById(R.id.imageView);//為該ImageView設定一個Tag,防止圖片錯位imageView.setTag(path);//為該ImageView設定顯示的圖片setImageForImageView(path, imageView);return view;}/** * 為ImageView設定圖片(Image) * 1 從緩衝中擷取圖片 * 2 若圖片不在緩衝中則為其設定預設圖片 */private void setImageForImageView(String imagePath, ImageView imageView) {Bitmap bitmap = getBitmapFromLruCache(imagePath);if (bitmap != null) {imageView.setImageBitmap(bitmap);} else {imageView.setImageResource(R.drawable.default_image);}}/** * 將圖片儲存到LruCache */public void addBitmapToLruCache(String key, Bitmap bitmap) {if (getBitmapFromLruCache(key) == null) {mLruCache.put(key, bitmap);}}/** * 從LruCache緩衝擷取圖片 */public Bitmap getBitmapFromLruCache(String key) {return mLruCache.get(key);} /** * 為GridView的item載入圖片 * @param firstVisibleItem GridView中可見的第一張圖片的下標 * @param visibleItemCount GridView中可見的圖片的數量 */private void loadBitmaps(int firstVisibleItem, int visibleItemCount) {try {for (int i = firstVisibleItem; i < firstVisibleItem + visibleItemCount; i++) {String imagePath = ImagesPath.IMAGES_PATH[i];Bitmap bitmap = getBitmapFromLruCache(imagePath);if (bitmap == null) {System.out.println("--->XXXXX 圖片"+imagePath+"不在緩衝中"+",所以從SDCard讀取");bitmap=BitmapFactory.decodeFile(imagePath);ImageView imageView = (ImageView) mGridView.findViewWithTag(imagePath);if (imageView != null && bitmap != null) {imageView.setImageBitmap(bitmap);}//將從SDCard讀取的圖片添加到LruCache中addBitmapToLruCache(imagePath, bitmap);} else {System.out.println("--->OOOOO 圖片在緩衝中="+imagePath+",從緩衝中取出即可");//依據Tag找到對應的ImageView顯示圖片ImageView imageView = (ImageView) mGridView.findViewWithTag(imagePath);if (imageView != null && bitmap != null) {imageView.setImageBitmap(bitmap);}}}} catch (Exception e) {e.printStackTrace();}}private class ScrollListenerImpl implements OnScrollListener{ /** * 通過onScrollStateChanged獲知:每次GridView停止滑動時載入圖片 * 但是存在一個特殊情況: * 當第一次入應用的時候,此時並沒有滑動螢幕的操作即不會調用onScrollStateChanged,但應該載入圖片. * 所以在此處做一個特殊的處理. * 即代碼: * if (isFirstEnterThisActivity && visibleItemCount > 0) { * loadBitmaps(firstVisibleItem, visibleItemCount); * isFirstEnterThisActivity = false; * } * * ------------------------------------------------------------ * * 其餘的都是正常情況. * 所以我們需要不斷儲存:firstVisibleItem和visibleItemCount * 從而便於中在onScrollStateChanged()判斷當停止滑動時載入圖片 * */@Overridepublic void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {mFirstVisibleItem = firstVisibleItem;mVisibleItemCount = visibleItemCount;if (isFirstEnterThisActivity && visibleItemCount > 0) {System.out.println("---> 第一次進入該介面");loadBitmaps(firstVisibleItem, visibleItemCount);isFirstEnterThisActivity = false;}}/** * GridView停止滑動時下載圖片 * 其餘情況下取消所有正在下載或者等待下載的任務 */@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {if (scrollState == SCROLL_STATE_IDLE) {System.out.println("---> GridView停止滑動 mFirstVisibleItem="+mFirstVisibleItem+",mVisibleItemCount="+mVisibleItemCount);loadBitmaps(mFirstVisibleItem, mVisibleItemCount);} }}}
ImagesPath如下:
package cc.testlrucache;public class ImagesPath {public final static String DIR="/mnt/sdcard/Test/";public final static String[] IMAGES_PATH = new String[] {DIR+"a.jpg",DIR+"b.jpg",DIR+"c.jpg",DIR+"d.jpg",DIR+"e.jpg",DIR+"f.jpg",DIR+"g.jpg",DIR+"h.jpg",DIR+"i.jpg",DIR+"j.jpg",DIR+"k.jpg",DIR+"l.jpg",DIR+"m.jpg",DIR+"n.jpg",DIR+"o.jpg",DIR+"p.jpg",DIR+"q.jpg",DIR+"r.jpg",DIR+"s.jpg",DIR+"t.jpg",DIR+"w.jpg",DIR+"x.jpg",DIR+"y.jpg",DIR+"z.jpg",DIR+"za.jpg",DIR+"zb.jpg",DIR+"zc.jpg",DIR+"zd.jpg",DIR+"ze.jpg",DIR+"zf.jpg",DIR+"zg.jpg",DIR+"zh.jpg",DIR+"zi.jpg",DIR+"zj.jpg",DIR+"zk.jpg",DIR+"zl.jpg",DIR+"zm.jpg"};}
main.xml如下:
gridview_item.xml如下: