Activity


  1. public class MainActivity extends Activity {
  2.     private GridView mPhotoWall;
  3.     private PhotoWallAdapter mAdapter;
  4.     @Override
  5.     protected void onCreate(Bundle savedInstanceState) {
  6.         super.onCreate(savedInstanceState);
  7.         setContentView(R.layout.activity_main);
  8.         mPhotoWall = (GridView) findViewById(R.id.photo_wall);
  9.         mAdapter = new PhotoWallAdapter(this, Images.imageThumbUrls, mPhotoWall);
  10.         mPhotoWall.setAdapter(mAdapter);
  11.     }
  12.     @Override
  13.     protected void onPause() {
  14.         super.onPause();
  15.         mAdapter.fluchCache();//将内存中的操作记录同步到日志文件journal当中,在Activity的onPause()方法中去调用一次flush()方法就可以了
  16.     }
  17.     @Override
  18.     protected void onDestroy() {
  19.         super.onDestroy();
  20.         mAdapter.cancelAllTasks();// 退出程序时结束所有的下载任务
  21.     }
  22. }
  23.  

Adapter

  1. /**
  2.  * GridView的适配器,负责异步从网络上下载图片展示在照片墙上。
  3.  */
  4. public class PhotoWallAdapter extends BaseAdapter {
  5.     private String[] urls;
  6.     private Context context;
  7.     /**记录所有正在下载或等待下载的任务 */
  8.     private Set<BitmapWorkerTask> taskCollection;
  9.     /**图片缓存技术的核心类,用于缓存所有下载好的图片,在程序内存达到设定值时会将最少最近使用的图片移除掉 */
  10.     private LruCache<String, Bitmap> mMemoryCache;
  11.     /**图片硬盘缓存核心类 */
  12.     private DiskLruCache mDiskLruCache;
  13.     /**记录每个子项的高度     */
  14.     private int mItemHeight = 0;
  15.     /** GridView的实例 */
  16.     private GridView mPhotoWall;
  17.     //******************************************************************************************************************************
  18.     public PhotoWallAdapter(Context context, String[] urls, GridView mPhotoWall) {
  19.         this.context = context;
  20.         this.urls = urls;
  21.         this.mPhotoWall = mPhotoWall;
  22.         taskCollection = new HashSet<BitmapWorkerTask>();
  23.         // 获取应用程序最大可用内存
  24.         int maxMemory = (int) Runtime.getRuntime().maxMemory();
  25.         // 设置图片缓存大小为程序最大可用内存的1/8
  26.         int cacheSize = maxMemory / 8;
  27.         mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
  28.             @Override
  29.             protected int sizeOf(String key, Bitmap bitmap) {
  30.                 return bitmap.getByteCount();
  31.             }
  32.         };
  33.         // 获取图片缓存路径
  34.         File cacheDir = getDiskCacheDir(context, "thumb");
  35.         if (!cacheDir.exists()) cacheDir.mkdirs();
  36.         // 创建DiskLruCache实例,初始化缓存数据
  37.         try {
  38.             mDiskLruCache = DiskLruCache.open(cacheDir, getAppVersion(context), 1, 10 * 1024 * 1024);
  39.         } catch (IOException e) {
  40.             e.printStackTrace();
  41.         }
  42.     }
  43.     //******************************************************************************************************************************
  44.     @SuppressLint("InflateParams")
  45.     @Override
  46.     public View getView(int position, View convertView, ViewGroup parent) {
  47.         View view;
  48.         if (convertView == null) view = LayoutInflater.from(context).inflate(R.layout.photo_layout, null);
  49.         else view = convertView;
  50.         ImageView imageView = (ImageView) view.findViewById(R.id.photo);
  51.         imageView.setTag(urls[position]);// 给ImageView设置一个Tag,保证异步加载图片时不会乱序
  52.         imageView.setImageResource(R.drawable.ic_launcher);
  53.         //每次加载图片的时候都优先去内存缓存当中读取,当读取不到的时候则回去硬盘缓存中读取,而如果硬盘缓存仍然读取不到的话,就从网络上请求原始数据
  54.         //不管是从硬盘缓存还是从网络获取,读取到了数据之后都添加到内存缓存当中,这样的话我们下次再去读取图片的时候就能迅速从内存当中读取到
  55.         loadBitmaps(imageView, urls[position]);
  56.         return view;
  57.     }
  58.     @Override
  59.     public int getCount() {
  60.         return urls == null ? 0 : urls.length;
  61.     }
  62.     @Override
  63.     public Object getItem(int position) {
  64.         return urls == null ? null : urls[position];
  65.     }
  66.     @Override
  67.     public long getItemId(int position) {
  68.         return position;
  69.     }
  70.     //******************************************************************************************************************************
  71.     /**
  72.      * 将一张图片存储到LruCache中。
  73.      * @param key LruCache的键,这里传入图片的URL地址。
  74.      * @param bitmap  LruCache的值,这里传入从网络上下载的Bitmap对象。
  75.      */
  76.     public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
  77.         if (getBitmapFromMemoryCache(key) == null) mMemoryCache.put(key, bitmap);
  78.     }
  79.     /**
  80.      * 从LruCache中获取一张图片,如果不存在就返回null。
  81.      * @param key LruCache的键,这里传入图片的URL地址。
  82.      * @return 对应传入键的Bitmap对象,或者null。
  83.      */
  84.     public Bitmap getBitmapFromMemoryCache(String key) {
  85.         return mMemoryCache.get(key);
  86.     }
  87.     /**
  88.      * 加载Bitmap对象。此方法会在LruCache中检查所有屏幕中可见的ImageView的Bitmap对象
  89.      * 如果发现任何一个ImageView的Bitmap对象不在缓存中,就会开启异步线程去下载图片。
  90.      */
  91.     public void loadBitmaps(ImageView imageView, String imageUrl) {
  92.         try {
  93.             //从内存中获取缓存,如果获取到了则直接调用ImageView的setImageBitmap()方法将图片显示到界面上
  94.             Bitmap bitmap = getBitmapFromMemoryCache(imageUrl);
  95.             if (bitmap != null) imageView.setImageBitmap(bitmap);
  96.             else {//如果内存中没有获取到,则开启一个BitmapWorkerTask任务来去异步加载图片
  97.                 BitmapWorkerTask task = new BitmapWorkerTask();
  98.                 taskCollection.add(task);//记录所有正在下载或等待下载的任务
  99.                 task.execute(imageUrl);
  100.             }
  101.         } catch (Exception e) {
  102.             e.printStackTrace();
  103.         }
  104.     }
  105.     /**
  106.      * 取消所有正在下载或等待下载的任务。
  107.      */
  108.     public void cancelAllTasks() {
  109.         if (taskCollection != null) {
  110.             for (BitmapWorkerTask task : taskCollection) {
  111.                 task.cancel(false);
  112.             }
  113.         }
  114.     }
  115.     /**
  116.      * 根据传入的uniqueName获取硬盘缓存的路径地址。
  117.      */
  118.     public File getDiskCacheDir(Context context, String uniqueName) {
  119.         String cachePath;
  120.         //当SD卡【存在】或者SD卡【不可被移除】时
  121.         if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || !Environment.isExternalStorageRemovable()) {
  122.             cachePath = context.getExternalCacheDir().getPath();//【SDCard/Android/data/包名/cache/】目录
  123.         } else cachePath = context.getCacheDir().getPath();//【/data/data/包名/cache/】目录
  124.         return new File(cachePath + File.separator + uniqueName);
  125.     }
  126.     /**
  127.      * 获取当前应用程序的版本号。
  128.      */
  129.     public int getAppVersion(Context context) {
  130.         try {
  131.             PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
  132.             return info.versionCode;
  133.         } catch (NameNotFoundException e) {
  134.             e.printStackTrace();
  135.         }
  136.         return 1;
  137.     }
  138.     /**
  139.      * 设置item子项的高度。
  140.      */
  141.     public void setItemHeight(int height) {
  142.         if (height == mItemHeight) return;
  143.         mItemHeight = height;
  144.         notifyDataSetChanged();
  145.     }
  146.     /**
  147.      * 使用MD5算法对传入的key进行加密并返回。
  148.      */
  149.     public String hashKeyForDisk(String key) {
  150.         String cacheKey;
  151.         try {
  152.             //为应用程序提供信息摘要算法的功能,如 MD5 或 SHA 算法。信息摘要是安全的单向哈希函数,它接收任意大小的数据,并输出固定长度的哈希值。
  153.             MessageDigest mDigest = MessageDigest.getInstance("MD5");
  154.             mDigest.update(key.getBytes());//使用指定的 byte 数组更新摘要
  155.             byte[] bytes = mDigest.digest();//通过执行诸如填充之类的最终操作完成哈希计算,返回存放哈希值结果的 byte 数组
  156.             StringBuilder sb = new StringBuilder();
  157.             for (int i = 0; i < bytes.length; i++) {
  158.                 String hex = Integer.toHexString(0xFF & bytes[i]);//以十六进制无符号整数形式返回一个整数参数的字符串表示形式
  159.                 if (hex.length() == 1) sb.append('0');
  160.                 sb.append(hex);
  161.             }
  162.             cacheKey = sb.toString();
  163.         } catch (NoSuchAlgorithmException e) {
  164.             cacheKey = String.valueOf(key.hashCode());
  165.         }
  166.         return cacheKey;
  167.     }
  168.     /**
  169.      * 将缓存记录同步到journal文件中。
  170.      */
  171.     public void fluchCache() {
  172.         if (mDiskLruCache != null) {
  173.             try {
  174.                 mDiskLruCache.flush();
  175.             } catch (IOException e) {
  176.                 e.printStackTrace();
  177.             }
  178.         }
  179.     }
  180.     //**********************************************************************************************************************
  181.     //                                                                                异步下载图片,并使用DiskLruCache进行缓存
  182.     //**********************************************************************************************************************
  183.     /**
  184.      * 异步下载图片的任务。
  185.      */
  186.     class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {
  187.         /**图片的URL地址 */
  188.         private String imageUrl;
  189.         @Override
  190.         protected Bitmap doInBackground(String... params) {
  191.             imageUrl = params[0];
  192.             FileDescriptor fileDescriptor = null;//与此流有关的文件描述符对象,主要实际用途是创建一个包含该结构的 FileInputStream 或 FileOutputStream
  193.             Snapshot snapShot = null;
  194.             FileInputStream fileInputStream = null;//缓存文件的输入流
  195.             try {
  196.                 // 首先根据图片的URL生成对应的MD5
  197.                 final String key = hashKeyForDisk(imageUrl);
  198.                 // 查找key对应的缓存
  199.                 snapShot = mDiskLruCache.get(key);
  200.                 // 如果没有找到对应的缓存,则准备从网络上请求数据,并写入缓存
  201.                 if (snapShot == null) {
  202.                     DiskLruCache.Editor editor = mDiskLruCache.edit(key);
  203.                     if (editor != null) {
  204.                         OutputStream outputStream = editor.newOutputStream(0);
  205.                         if (downloadUrlToStream(imageUrl, outputStream)) editor.commit();
  206.                         else editor.abort();
  207.                     }
  208.                     // 缓存被写入后,再次查找key对应的缓存
  209.                     snapShot = mDiskLruCache.get(key);
  210.                 }
  211.                 if (snapShot != null) {
  212.                     fileInputStream = (FileInputStream) snapShot.getInputStream(0);
  213.                     fileDescriptor = fileInputStream.getFD();//返回表示到文件系统中实际文件的连接的 FileDescriptor 对象,该文件系统正被此 FileInputStream 使用
  214.                 }
  215.                 // 将缓存数据解析成Bitmap对象
  216.                 Bitmap bitmap = null;
  217.                 if (fileDescriptor != null) bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
  218.                 // 将Bitmap对象添加到内存缓存当中
  219.                 if (bitmap != null) addBitmapToMemoryCache(params[0], bitmap);
  220.                 return bitmap;
  221.             } catch (IOException e) {
  222.                 e.printStackTrace();
  223.             } finally {
  224.                 if (fileDescriptor == null && fileInputStream != null) {
  225.                     try {
  226.                         fileInputStream.close();
  227.                     } catch (IOException e) {
  228.                     }
  229.                 }
  230.             }
  231.             return null;
  232.         }
  233.         @Override
  234.         protected void onPostExecute(Bitmap bitmap) {
  235.             super.onPostExecute(bitmap);
  236.             // 根据Tag找到相应的ImageView控件,将下载好的图片显示出来。
  237.             ImageView imageView = (ImageView) mPhotoWall.findViewWithTag(imageUrl);
  238.             if (imageView != null && bitmap != null) imageView.setImageBitmap(bitmap);
  239.             taskCollection.remove(this);
  240.         }
  241.         /**
  242.          * 建立HTTP请求,并获取Bitmap对象。
  243.          * @param imageUrl 图片的URL地址
  244.          * @return 解析后的Bitmap对象
  245.          */
  246.         private boolean downloadUrlToStream(String urlString, OutputStream outputStream) {
  247.             HttpURLConnection urlConnection = null;
  248.             BufferedOutputStream out = null;
  249.             BufferedInputStream in = null;
  250.             try {
  251.                 final URL url = new URL(urlString);
  252.                 urlConnection = (HttpURLConnection) url.openConnection();
  253.                 in = new BufferedInputStream(urlConnection.getInputStream(), 8 * 1024);
  254.                 out = new BufferedOutputStream(outputStream, 8 * 1024);
  255.                 int b;
  256.                 while ((= in.read()) != -1) {
  257.                     out.write(b);
  258.                 }
  259.                 return true;
  260.             } catch (final IOException e) {
  261.                 e.printStackTrace();
  262.             } finally {
  263.                 if (urlConnection != null) {
  264.                     urlConnection.disconnect();
  265.                 }
  266.                 try {
  267.                     if (out != null) {
  268.                         out.close();
  269.                     }
  270.                     if (in != null) {
  271.                         in.close();
  272.                     }
  273.                 } catch (final IOException e) {
  274.                     e.printStackTrace();
  275.                 }
  276.             }
  277.             return false;
  278.         }
  279.     }
  280. }
  281.  

清单文件

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3.     package="com.bqt.cache"
  4.     android:versionCode="1"
  5.     android:versionName="1.0" >
  6.     <uses-sdk
  7.         android:minSdkVersion="14"
  8.         android:targetSdkVersion="17" />
  9.     <uses-permission android:name="android.permission.INTERNET" />
  10.     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  11.     <application
  12.         android:allowBackup="true"
  13.         android:icon="@drawable/ic_launcher"
  14.         android:label="@string/app_name"
  15.         android:theme="@style/AppTheme" >
  16.         <activity
  17.             android:name=".MainActivity"
  18.             android:label="@string/app_name" >
  19.             <intent-filter>
  20.                 <action android:name="android.intent.action.MAIN" />
  21.                 <category android:name="android.intent.category.LAUNCHER" />
  22.             </intent-filter>
  23.         </activity>
  24.     </application>
  25. </manifest>
  26.  

附件列表

综合使用LruCache和DiskLruCache 缓存图片的更多相关文章

  1. android--------Universal-Image-Loader图片加载框架和结合LruCache缓存图片

    本博客包含包含Android-Universal-Image-Loader 网络图片加载框架实现图片加载和结合universal-image-loader与LruCache来自定义缓存图片,可以设置缓 ...

  2. 安卓开发笔记——关于图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)

    在开发安卓应用中避免不了要使用到网络图片,获取网络图片很简单,但是需要付出一定的代价——流量.对于少数的图片而言问题不大,但如果手机应用中包含大量的图片,这势必会耗费用户的一定流量,如果我们不加以处理 ...

  3. Android Volley框架的使用(四)图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)

    在开发安卓应用中避免不了要使用到网络图片,获取网络图片很简单,但是需要付出一定的代价——流量.对于少数的图片而言问题不大,但如果手机应用中包含大量的图片,这势必会耗费用户的一定流量,如果我们不加以处理 ...

  4. Cache【硬盘缓存工具类(包含内存缓存LruCache和磁盘缓存DiskLruCache)】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 内存缓存LruCache和磁盘缓存DiskLruCache的封装类,主要用于图片缓存. 效果图 代码分析 内存缓存LruCache和 ...

  5. LruCache DiskLruCache 缓存 简介 案例 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  6. 网络图片的获取以及二级缓存策略(Volley框架+内存LruCache+磁盘DiskLruCache)

    在开发安卓应用中避免不了要使用到网络图片,获取网络图片很简单,但是需要付出一定的代价——流量.对于少数的图片而言问题不大,但如果手机应用中包含大量的图片,这势必会耗费用户的一定流量,如果我们不加以处理 ...

  7. Android 使用 LruCache 缓存图片

    在你应用程序的 UI 界面加载一张图片是一件很简单的事情,但是当你需要在界面上加载一大堆图片的时候,情况就变得复杂起来.在很多情况下,(比如使用 ListView, GridView 或者 ViewP ...

  8. Android使用 LruCache 缓存图片

    摘要:在你应用程序的UI界面加载一张图片是一件很简单的事情,但是当你需要在界面上加载一大堆图片的时候,情况就变得复杂起来. 使用图片缓存技术 在 你应用程序的UI界面加载一张图片是一件很简单的事情,但 ...

  9. LruCache--远程图片获取与本地缓存

    Class Overview A cache that holds strong references to a limited number of values. Each time a value ...

随机推荐

  1. Static Class (静态类)

    一般情况下是不可以用static修饰类的.如果一定要用static修饰类的话,通常static修饰的是匿名内部类. 在一个类中创建另外一个类,叫做成员内部类.这个成员内部类可以静态的(利用static ...

  2. 开始编写正式的iOS 程序(iOS编程指导)

    App设计基础 在确定了你的App主要功能后,需要把它转化为代码.如果你是第一次开发属于自己的iOS App,需要花些时间熟悉基本概念.iOS内置了很多设计样式,多了解下能对你以后有帮助. 初稿 设计 ...

  3. gearmand的安装

    1.安装gperf libuuid-devel yum install -y gperf libuuid-devel 2.安装 libevent yum install libevent libeve ...

  4. IOS开发之UIScrollView

    一.UIScrollView的边界处理问题: bounds属性: (1)当bounces属性设置为YES时,当UIScrollView中图片滑动到边界的时候会出现弹动的效果,就像是Linux中的果冻效 ...

  5. JavaScript-学习一获取表单的值

    <!DOCTYPE html><html><head> <meta charset="utf-8"> <title>he ...

  6. [HTML5 Canvas学习] 基础知识

    HTML5 canvas元素通过脚本语言(通常是Javascript) 绘制图形, 它仅仅是一个绘图环境,需要通过getContext('2d')方法获得绘图环境对象,使用绘图环境对象在canvas元 ...

  7. text-overflow:ellipsis 的应用(转载)

    关键字: text-overflow:ellipsis 语法:text-overflow : clip | ellipsis 取值: clip :默认值 .不显示省略标记(...),而是简单的裁切. ...

  8. Hibernate的批量处理

    Hibernate完全以面向对象的方式操作数据库,当程序员以面向对象的方式操作持久化对象时,将自动转换为对数据的操作.例如我们Session的delete()方法,来删除持久化对象,Hibernate ...

  9. 转:视觉中国的NoSQL之路:从MySQL到MongoDB

    起因 视觉中国网站(www.chinavisual.com)是国内最大的创意人群的专业网站.2009年以前,同很多公司一样,我们的CMS和社区产品都构建于PHP+Nginx+MySQL之上:MySQL ...

  10. LED驅動芯片 兩種恒流控制方式

    下面要說的是,兩種恒流控制模式的開關電源,從而產生兩種做法.這兩種做法無論是原理,還是器件應用,還是性能差別,相當都較大.     首先說原理.第一種以現在恒流型LED專用IC為代表,主要如9910系 ...