LruCache为GridView异步加载大量网络图片

MainActivity如下:

  1. import android.os.Bundle;  
  2. import android.widget.GridView;  
  3. import android.app.Activity;  
  4. /** 
  5.  * Demo描述: 
  6.  * 在GridView中采用LruCache异步加载大量图片,避免OOM 
  7.  *  
  8.  * 学习资料: 
  9.  * http://blog.csdn.net/guolin_blog/article/details/9526203 
  10.  * Thank you very much 
  11.  */  
  12.   
  13. public class MainActivity extends Activity {  
  14.     private GridView mGridView;  
  15.     private GridViewAdapter mGridViewAdapter;  
  16.     @Override  
  17.     protected void onCreate(Bundle savedInstanceState) {  
  18.         super.onCreate(savedInstanceState);  
  19.         setContentView(R.layout.main);  
  20.         init();  
  21.     }  
  22.       
  23.     private void init(){  
  24.         mGridView = (GridView) findViewById(R.id.gridView);  
  25.         mGridViewAdapter = new GridViewAdapter(this, 0, ImagesUrl.Urls, mGridView);  
  26.         mGridView.setAdapter(mGridViewAdapter);  
  27.     }  
  28.   
  29.     //取消所有的下载任务  
  30.     @Override  
  31.     protected void onDestroy() {  
  32.         super.onDestroy();  
  33.         mGridViewAdapter.cancelAllTasks();  
  34.     }  

 

GridViewAdapter如下:

  1. import java.net.HttpURLConnection;  
  2. import java.net.URL;  
  3. import java.util.HashSet;  
  4. import android.annotation.SuppressLint;  
  5. import android.content.Context;  
  6. import android.graphics.Bitmap;  
  7. import android.graphics.BitmapFactory;  
  8. import android.os.AsyncTask;  
  9. import android.support.v4.util.LruCache;  
  10. import android.view.LayoutInflater;  
  11. import android.view.View;  
  12. import android.view.ViewGroup;  
  13. import android.widget.AbsListView;  
  14. import android.widget.AbsListView.OnScrollListener;  
  15. import android.widget.ArrayAdapter;  
  16. import android.widget.GridView;  
  17. import android.widget.ImageView;  
  18. /** 
  19.  * LruCache的流程分析: 
  20.  * 我们从第一次进入应用的情况下开始 
  21.  * 1 依据图片的Url从LruCache缓存中取图片. 
  22.  *   若图片存在缓存中,则显示该图片;否则显示默认图片 
  23.  * 2 因为是第一次进入该界面所以会执行: 
  24.  *   loadBitmaps(firstVisibleItem, visibleItemCount); 
  25.  *   我们从loadBitmaps()方法作为切入点,继续往下梳理 
  26.  * 3 尝试从LruCache缓存中取图片.如果在显示即可,否则进入4 
  27.  * 4 开启一个异步任务下载图片.下载完成后显示图片,并且将 
  28.  *   该图片存入LruCache缓存中 
  29.  *    
  30.  * 在停止滑动时,会调用loadBitmaps(firstVisibleItem, visibleItemCount) 
  31.  * 情况与上类似 
  32.  */  
  33. @SuppressLint("NewApi")  
  34. public class GridViewAdapter extends ArrayAdapter<String> {  
  35.       
  36.     private GridView mGridView;  
  37.     //图片缓存类  
  38.     private LruCache<String, Bitmap> mLruCache;  
  39.     //记录所有正在下载或等待下载的任务  
  40.     private HashSet<DownloadBitmapAsyncTask> mDownloadBitmapAsyncTaskHashSet;  
  41.     //GridView中可见的第一张图片的下标  
  42.     private int mFirstVisibleItem;  
  43.     //GridView中可见的图片的数量  
  44.     private int mVisibleItemCount;  
  45.     //记录是否是第一次进入该界面  
  46.     private boolean isFirstEnterThisActivity = true;  
  47.   
  48.     public GridViewAdapter(Context context, int textViewResourceId,String[] objects, GridView gridView) {  
  49.         super(context, textViewResourceId, objects);  
  50.           
  51.         mGridView = gridView;  
  52.         mGridView.setOnScrollListener(new ScrollListenerImpl());  
  53.           
  54.         mDownloadBitmapAsyncTaskHashSet = new HashSet<DownloadBitmapAsyncTask>();  
  55.           
  56.         // 获取应用程序最大可用内存  
  57.         int maxMemory = (int) Runtime.getRuntime().maxMemory();  
  58.         // 设置图片缓存大小为maxMemory的1/6  
  59.         int cacheSize = maxMemory/6;  
  60.           
  61.         mLruCache = new LruCache<String, Bitmap>(cacheSize) {  
  62.             @Override  
  63.             protected int sizeOf(String key, Bitmap bitmap) {  
  64.                 return bitmap.getByteCount();  
  65.             }  
  66.         };  
  67.           
  68.     }  
  69.   
  70.     @Override  
  71.     public View getView(int position, View convertView, ViewGroup parent) {  
  72.         String url = getItem(position);  
  73.         View view;  
  74.         if (convertView == null) {  
  75.             view = LayoutInflater.from(getContext()).inflate(R.layout.gridview_item, null);  
  76.         } else {  
  77.             view = convertView;  
  78.         }  
  79.         ImageView imageView = (ImageView) view.findViewById(R.id.imageView);  
  80.         //为该ImageView设置一个Tag,防止图片错位  
  81.         imageView.setTag(url);  
  82.         //为该ImageView设置显示的图片  
  83.         setImageForImageView(url, imageView);  
  84.         return view;  
  85.     }  
  86.   
  87.     /** 
  88.      * 为ImageView设置图片(Image) 
  89.      * 1 从缓存中获取图片 
  90.      * 2 若图片不在缓存中则为其设置默认图片 
  91.      */  
  92.     private void setImageForImageView(String imageUrl, ImageView imageView) {  
  93.         Bitmap bitmap = getBitmapFromLruCache(imageUrl);  
  94.         if (bitmap != null) {  
  95.             imageView.setImageBitmap(bitmap);  
  96.         } else {  
  97.             imageView.setImageResource(R.drawable.default_image);  
  98.         }  
  99.     }  
  100.   
  101.     /** 
  102.      * 将图片存储到LruCache 
  103.      */  
  104.     public void addBitmapToLruCache(String key, Bitmap bitmap) {  
  105.         if (getBitmapFromLruCache(key) == null) {  
  106.             mLruCache.put(key, bitmap);  
  107.         }  
  108.     }  
  109.   
  110.     /** 
  111.      * 从LruCache缓存获取图片 
  112.      */  
  113.     public Bitmap getBitmapFromLruCache(String key) {  
  114.         return mLruCache.get(key);  
  115.     }  
  116.   
  117.       
  118.   
  119.    /** 
  120.     * 为GridView的item加载图片 
  121.     *  
  122.     * @param firstVisibleItem  
  123.     * GridView中可见的第一张图片的下标 
  124.     *  
  125.     * @param visibleItemCount  
  126.     * GridView中可见的图片的数量 
  127.     *  
  128.     */  
  129.     private void loadBitmaps(int firstVisibleItem, int visibleItemCount) {  
  130.         try {  
  131.             for (int i = firstVisibleItem; i < firstVisibleItem + visibleItemCount; i++) {  
  132.                 String imageUrl = ImagesUrl.Urls[i];  
  133.                 Bitmap bitmap = getBitmapFromLruCache(imageUrl);  
  134.                 if (bitmap == null) {  
  135.                     DownloadBitmapAsyncTask downloadBitmapAsyncTask = new DownloadBitmapAsyncTask();  
  136.                     mDownloadBitmapAsyncTaskHashSet.add(downloadBitmapAsyncTask);  
  137.                     downloadBitmapAsyncTask.execute(imageUrl);  
  138.                 } else {  
  139.                     //依据Tag找到对应的ImageView显示图片  
  140.                     ImageView imageView = (ImageView) mGridView.findViewWithTag(imageUrl);  
  141.                     if (imageView != null && bitmap != null) {  
  142.                         imageView.setImageBitmap(bitmap);  
  143.                     }  
  144.                 }  
  145.             }  
  146.         } catch (Exception e) {  
  147.             e.printStackTrace();  
  148.         }  
  149.     }  
  150.   
  151.     /** 
  152.      * 取消所有正在下载或等待下载的任务 
  153.      */  
  154.     public void cancelAllTasks() {  
  155.         if (mDownloadBitmapAsyncTaskHashSet != null) {  
  156.             for (DownloadBitmapAsyncTask task : mDownloadBitmapAsyncTaskHashSet) {  
  157.                 task.cancel(false);  
  158.             }  
  159.         }  
  160.     }  
  161.       
  162.       
  163.     private class ScrollListenerImpl implements OnScrollListener{  
  164.         /** 
  165.          *  
  166.          * 我们的本意是通过onScrollStateChanged获知:每次GridView停止滑动时加载图片 
  167.          * 但是存在一个特殊情况: 
  168.          * 当第一次入应用的时候,此时并没有滑动屏幕的操作即不会调用onScrollStateChanged,但应该加载图片. 
  169.          * 所以在此处做一个特殊的处理. 
  170.          * 即代码: 
  171.          * if (isFirstEnterThisActivity && visibleItemCount > 0) { 
  172.          *      loadBitmaps(firstVisibleItem, visibleItemCount); 
  173.          *      isFirstEnterThisActivity = false; 
  174.          *    } 
  175.          *     
  176.          * ------------------------------------------------------------ 
  177.          *  
  178.          * 其余的都是正常情况. 
  179.          * 所以我们需要不断保存:firstVisibleItem和visibleItemCount 
  180.          * 从而便于中在onScrollStateChanged()判断当停止滑动时加载图片 
  181.          *  
  182.          */  
  183.         @Override  
  184.         public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {  
  185.             mFirstVisibleItem = firstVisibleItem;  
  186.             mVisibleItemCount = visibleItemCount;  
  187.             if (isFirstEnterThisActivity && visibleItemCount > 0) {  
  188.                 loadBitmaps(firstVisibleItem, visibleItemCount);  
  189.                 isFirstEnterThisActivity = false;  
  190.             }  
  191.         }  
  192.           
  193.         /** 
  194.          *  GridView停止滑动时下载图片 
  195.          *  其余情况下取消所有正在下载或者等待下载的任务 
  196.          */  
  197.         @Override  
  198.         public void onScrollStateChanged(AbsListView view, int scrollState) {  
  199.             if (scrollState == SCROLL_STATE_IDLE) {  
  200.                 loadBitmaps(mFirstVisibleItem, mVisibleItemCount);  
  201.             } else {  
  202.                 cancelAllTasks();  
  203.             }  
  204.         }  
  205.           
  206.     }  
  207.   
  208.     /** 
  209.      * 下载图片的异步任务 
  210.      */  
  211.     class DownloadBitmapAsyncTask extends AsyncTask<String, Void, Bitmap> {  
  212.         private String imageUrl;  
  213.         @Override  
  214.         protected Bitmap doInBackground(String... params) {  
  215.             imageUrl = params[0];  
  216.             Bitmap bitmap = downloadBitmap(params[0]);  
  217.             if (bitmap != null) {  
  218.                 //下载完后,将其缓存到LrcCache  
  219.                 addBitmapToLruCache(params[0], bitmap);  
  220.             }  
  221.             return bitmap;  
  222.         }  
  223.   
  224.         @Override  
  225.         protected void onPostExecute(Bitmap bitmap) {  
  226.             super.onPostExecute(bitmap);  
  227.             //下载完成后,找到其对应的ImageView显示图片  
  228.             ImageView imageView = (ImageView) mGridView.findViewWithTag(imageUrl);  
  229.             if (imageView != null && bitmap != null) {  
  230.                 imageView.setImageBitmap(bitmap);  
  231.             }  
  232.             mDownloadBitmapAsyncTaskHashSet.remove(this);  
  233.         }  
  234.     }  
  235.   
  236.     // 获取Bitmap  
  237.     private Bitmap downloadBitmap(String imageUrl) {  
  238.         Bitmap bitmap = null;  
  239.         HttpURLConnection httpURLConnection = null;  
  240.         try {  
  241.             URL url = new URL(imageUrl);  
  242.             httpURLConnection = (HttpURLConnection) url.openConnection();  
  243.             httpURLConnection.setConnectTimeout(5 * 1000);  
  244.             httpURLConnection.setReadTimeout(10 * 1000);  
  245.             httpURLConnection.setDoInput(true);  
  246.             httpURLConnection.setDoOutput(true);  
  247.             bitmap = BitmapFactory.decodeStream(httpURLConnection.getInputStream());  
  248.         } catch (Exception e) {  
  249.             e.printStackTrace();  
  250.         } finally {  
  251.             if (httpURLConnection != null) {  
  252.                 httpURLConnection.disconnect();  
  253.             }  
  254.         }  
  255.         return bitmap;  
  256.     }  
  257.   
  258. }  

 

ImagesUrl如下:

  1. public class ImagesUrl {  
  2.   
  3.     public final static String[] Urls = new String[] {  
  4.             "https://lh6.googleusercontent.com/-55osAWw3x0Q/URquUtcFr5I/AAAAAAAAAbs/rWlj1RUKrYI/s160-c/A%252520Photographer.jpg",  
  5.             "https://lh4.googleusercontent.com/--dq8niRp7W4/URquVgmXvgI/AAAAAAAAAbs/-gnuLQfNnBA/s160-c/A%252520Song%252520of%252520Ice%252520and%252520Fire.jpg",  
  6.             "https://lh5.googleusercontent.com/-7qZeDtRKFKc/URquWZT1gOI/AAAAAAAAAbs/hqWgteyNXsg/s160-c/Another%252520Rockaway%252520Sunset.jpg",  
  7.             "https://lh3.googleusercontent.com/--L0Km39l5J8/URquXHGcdNI/AAAAAAAAAbs/3ZrSJNrSomQ/s160-c/Antelope%252520Butte.jpg",  
  8.             "https://lh6.googleusercontent.com/-8HO-4vIFnlw/URquZnsFgtI/AAAAAAAAAbs/WT8jViTF7vw/s160-c/Antelope%252520Hallway.jpg",  
  9.             "https://lh4.googleusercontent.com/-WIuWgVcU3Qw/URqubRVcj4I/AAAAAAAAAbs/YvbwgGjwdIQ/s160-c/Antelope%252520Walls.jpg",  
  10.             "https://lh6.googleusercontent.com/-UBmLbPELvoQ/URqucCdv0kI/AAAAAAAAAbs/IdNhr2VQoQs/s160-c/Apre%2525CC%252580s%252520la%252520Pluie.jpg"};

 

posted @ 2015-11-16 16:54  冷月舞痕  阅读(225)  评论(0编辑  收藏  举报