综合使用LruCache和DiskLruCache 缓存图片
Activity
public class MainActivity extends Activity {private GridView mPhotoWall;private PhotoWallAdapter mAdapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mPhotoWall = (GridView) findViewById(R.id.photo_wall);mAdapter = new PhotoWallAdapter(this, Images.imageThumbUrls, mPhotoWall);mPhotoWall.setAdapter(mAdapter);}@Overrideprotected void onPause() {super.onPause();mAdapter.fluchCache();//将内存中的操作记录同步到日志文件journal当中,在Activity的onPause()方法中去调用一次flush()方法就可以了}@Overrideprotected void onDestroy() {super.onDestroy();mAdapter.cancelAllTasks();// 退出程序时结束所有的下载任务}}
Adapter
/*** GridView的适配器,负责异步从网络上下载图片展示在照片墙上。*/public class PhotoWallAdapter extends BaseAdapter {private String[] urls;private Context context;/**记录所有正在下载或等待下载的任务 */private Set<BitmapWorkerTask> taskCollection;/**图片缓存技术的核心类,用于缓存所有下载好的图片,在程序内存达到设定值时会将最少最近使用的图片移除掉 */private LruCache<String, Bitmap> mMemoryCache;/**图片硬盘缓存核心类 */private DiskLruCache mDiskLruCache;/**记录每个子项的高度 */private int mItemHeight = 0;/** GridView的实例 */private GridView mPhotoWall;//******************************************************************************************************************************public PhotoWallAdapter(Context context, String[] urls, GridView mPhotoWall) {this.context = context;this.urls = urls;this.mPhotoWall = mPhotoWall;taskCollection = new HashSet<BitmapWorkerTask>();// 获取应用程序最大可用内存int maxMemory = (int) Runtime.getRuntime().maxMemory();// 设置图片缓存大小为程序最大可用内存的1/8int cacheSize = maxMemory / 8;mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {@Overrideprotected int sizeOf(String key, Bitmap bitmap) {return bitmap.getByteCount();}};// 获取图片缓存路径File cacheDir = getDiskCacheDir(context, "thumb");if (!cacheDir.exists()) cacheDir.mkdirs();// 创建DiskLruCache实例,初始化缓存数据try {mDiskLruCache = DiskLruCache.open(cacheDir, getAppVersion(context), 1, 10 * 1024 * 1024);} catch (IOException e) {e.printStackTrace();}}//******************************************************************************************************************************@SuppressLint("InflateParams")@Overridepublic View getView(int position, View convertView, ViewGroup parent) {View view;if (convertView == null) view = LayoutInflater.from(context).inflate(R.layout.photo_layout, null);else view = convertView;ImageView imageView = (ImageView) view.findViewById(R.id.photo);imageView.setTag(urls[position]);// 给ImageView设置一个Tag,保证异步加载图片时不会乱序imageView.setImageResource(R.drawable.ic_launcher);//每次加载图片的时候都优先去内存缓存当中读取,当读取不到的时候则回去硬盘缓存中读取,而如果硬盘缓存仍然读取不到的话,就从网络上请求原始数据//不管是从硬盘缓存还是从网络获取,读取到了数据之后都添加到内存缓存当中,这样的话我们下次再去读取图片的时候就能迅速从内存当中读取到loadBitmaps(imageView, urls[position]);return view;}@Overridepublic int getCount() {return urls == null ? 0 : urls.length;}@Overridepublic Object getItem(int position) {return urls == null ? null : urls[position];}@Overridepublic long getItemId(int position) {return position;}//******************************************************************************************************************************/*** 将一张图片存储到LruCache中。* @param key LruCache的键,这里传入图片的URL地址。* @param bitmap LruCache的值,这里传入从网络上下载的Bitmap对象。*/public void addBitmapToMemoryCache(String key, Bitmap bitmap) {if (getBitmapFromMemoryCache(key) == null) mMemoryCache.put(key, bitmap);}/*** 从LruCache中获取一张图片,如果不存在就返回null。* @param key LruCache的键,这里传入图片的URL地址。* @return 对应传入键的Bitmap对象,或者null。*/public Bitmap getBitmapFromMemoryCache(String key) {return mMemoryCache.get(key);}/*** 加载Bitmap对象。此方法会在LruCache中检查所有屏幕中可见的ImageView的Bitmap对象* 如果发现任何一个ImageView的Bitmap对象不在缓存中,就会开启异步线程去下载图片。*/public void loadBitmaps(ImageView imageView, String imageUrl) {try {//从内存中获取缓存,如果获取到了则直接调用ImageView的setImageBitmap()方法将图片显示到界面上Bitmap bitmap = getBitmapFromMemoryCache(imageUrl);if (bitmap != null) imageView.setImageBitmap(bitmap);else {//如果内存中没有获取到,则开启一个BitmapWorkerTask任务来去异步加载图片BitmapWorkerTask task = new BitmapWorkerTask();taskCollection.add(task);//记录所有正在下载或等待下载的任务task.execute(imageUrl);}} catch (Exception e) {e.printStackTrace();}}/*** 取消所有正在下载或等待下载的任务。*/public void cancelAllTasks() {if (taskCollection != null) {for (BitmapWorkerTask task : taskCollection) {task.cancel(false);}}}/*** 根据传入的uniqueName获取硬盘缓存的路径地址。*/public File getDiskCacheDir(Context context, String uniqueName) {String cachePath;//当SD卡【存在】或者SD卡【不可被移除】时if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || !Environment.isExternalStorageRemovable()) {cachePath = context.getExternalCacheDir().getPath();//【SDCard/Android/data/包名/cache/】目录} else cachePath = context.getCacheDir().getPath();//【/data/data/包名/cache/】目录return new File(cachePath + File.separator + uniqueName);}/*** 获取当前应用程序的版本号。*/public int getAppVersion(Context context) {try {PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);return info.versionCode;} catch (NameNotFoundException e) {e.printStackTrace();}return 1;}/*** 设置item子项的高度。*/public void setItemHeight(int height) {if (height == mItemHeight) return;mItemHeight = height;notifyDataSetChanged();}/*** 使用MD5算法对传入的key进行加密并返回。*/public String hashKeyForDisk(String key) {String cacheKey;try {//为应用程序提供信息摘要算法的功能,如 MD5 或 SHA 算法。信息摘要是安全的单向哈希函数,它接收任意大小的数据,并输出固定长度的哈希值。MessageDigest mDigest = MessageDigest.getInstance("MD5");mDigest.update(key.getBytes());//使用指定的 byte 数组更新摘要byte[] bytes = mDigest.digest();//通过执行诸如填充之类的最终操作完成哈希计算,返回存放哈希值结果的 byte 数组StringBuilder sb = new StringBuilder();for (int i = 0; i < bytes.length; i++) {String hex = Integer.toHexString(0xFF & bytes[i]);//以十六进制无符号整数形式返回一个整数参数的字符串表示形式if (hex.length() == 1) sb.append('0');sb.append(hex);}cacheKey = sb.toString();} catch (NoSuchAlgorithmException e) {cacheKey = String.valueOf(key.hashCode());}return cacheKey;}/*** 将缓存记录同步到journal文件中。*/public void fluchCache() {if (mDiskLruCache != null) {try {mDiskLruCache.flush();} catch (IOException e) {e.printStackTrace();}}}//**********************************************************************************************************************// 异步下载图片,并使用DiskLruCache进行缓存//**********************************************************************************************************************/*** 异步下载图片的任务。*/class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {/**图片的URL地址 */private String imageUrl;@Overrideprotected Bitmap doInBackground(String... params) {imageUrl = params[0];FileDescriptor fileDescriptor = null;//与此流有关的文件描述符对象,主要实际用途是创建一个包含该结构的 FileInputStream 或 FileOutputStreamSnapshot snapShot = null;FileInputStream fileInputStream = null;//缓存文件的输入流try {// 首先根据图片的URL生成对应的MD5final String key = hashKeyForDisk(imageUrl);// 查找key对应的缓存snapShot = mDiskLruCache.get(key);// 如果没有找到对应的缓存,则准备从网络上请求数据,并写入缓存if (snapShot == null) {DiskLruCache.Editor editor = mDiskLruCache.edit(key);if (editor != null) {OutputStream outputStream = editor.newOutputStream(0);if (downloadUrlToStream(imageUrl, outputStream)) editor.commit();else editor.abort();}// 缓存被写入后,再次查找key对应的缓存snapShot = mDiskLruCache.get(key);}if (snapShot != null) {fileInputStream = (FileInputStream) snapShot.getInputStream(0);fileDescriptor = fileInputStream.getFD();//返回表示到文件系统中实际文件的连接的 FileDescriptor 对象,该文件系统正被此 FileInputStream 使用}// 将缓存数据解析成Bitmap对象Bitmap bitmap = null;if (fileDescriptor != null) bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);// 将Bitmap对象添加到内存缓存当中if (bitmap != null) addBitmapToMemoryCache(params[0], bitmap);return bitmap;} catch (IOException e) {e.printStackTrace();} finally {if (fileDescriptor == null && fileInputStream != null) {try {fileInputStream.close();} catch (IOException e) {}}}return null;}@Overrideprotected void onPostExecute(Bitmap bitmap) {super.onPostExecute(bitmap);// 根据Tag找到相应的ImageView控件,将下载好的图片显示出来。ImageView imageView = (ImageView) mPhotoWall.findViewWithTag(imageUrl);if (imageView != null && bitmap != null) imageView.setImageBitmap(bitmap);taskCollection.remove(this);}/*** 建立HTTP请求,并获取Bitmap对象。* @param imageUrl 图片的URL地址* @return 解析后的Bitmap对象*/private boolean downloadUrlToStream(String urlString, OutputStream outputStream) {HttpURLConnection urlConnection = null;BufferedOutputStream out = null;BufferedInputStream in = null;try {final URL url = new URL(urlString);urlConnection = (HttpURLConnection) url.openConnection();in = new BufferedInputStream(urlConnection.getInputStream(), 8 * 1024);out = new BufferedOutputStream(outputStream, 8 * 1024);int b;while ((b = in.read()) != -1) {out.write(b);}return true;} catch (final IOException e) {e.printStackTrace();} finally {if (urlConnection != null) {urlConnection.disconnect();}try {if (out != null) {out.close();}if (in != null) {in.close();}} catch (final IOException e) {e.printStackTrace();}}return false;}}}
清单文件
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.bqt.cache"android:versionCode="1"android:versionName="1.0" ><uses-sdkandroid:minSdkVersion="14"android:targetSdkVersion="17" /><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><applicationandroid:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme" ><activityandroid:name=".MainActivity"android:label="@string/app_name" ><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>
附件列表
综合使用LruCache和DiskLruCache 缓存图片的更多相关文章
- android--------Universal-Image-Loader图片加载框架和结合LruCache缓存图片
本博客包含包含Android-Universal-Image-Loader 网络图片加载框架实现图片加载和结合universal-image-loader与LruCache来自定义缓存图片,可以设置缓 ...
- 安卓开发笔记——关于图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)
在开发安卓应用中避免不了要使用到网络图片,获取网络图片很简单,但是需要付出一定的代价——流量.对于少数的图片而言问题不大,但如果手机应用中包含大量的图片,这势必会耗费用户的一定流量,如果我们不加以处理 ...
- Android Volley框架的使用(四)图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)
在开发安卓应用中避免不了要使用到网络图片,获取网络图片很简单,但是需要付出一定的代价——流量.对于少数的图片而言问题不大,但如果手机应用中包含大量的图片,这势必会耗费用户的一定流量,如果我们不加以处理 ...
- Cache【硬盘缓存工具类(包含内存缓存LruCache和磁盘缓存DiskLruCache)】
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 内存缓存LruCache和磁盘缓存DiskLruCache的封装类,主要用于图片缓存. 效果图 代码分析 内存缓存LruCache和 ...
- LruCache DiskLruCache 缓存 简介 案例 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- 网络图片的获取以及二级缓存策略(Volley框架+内存LruCache+磁盘DiskLruCache)
在开发安卓应用中避免不了要使用到网络图片,获取网络图片很简单,但是需要付出一定的代价——流量.对于少数的图片而言问题不大,但如果手机应用中包含大量的图片,这势必会耗费用户的一定流量,如果我们不加以处理 ...
- Android 使用 LruCache 缓存图片
在你应用程序的 UI 界面加载一张图片是一件很简单的事情,但是当你需要在界面上加载一大堆图片的时候,情况就变得复杂起来.在很多情况下,(比如使用 ListView, GridView 或者 ViewP ...
- Android使用 LruCache 缓存图片
摘要:在你应用程序的UI界面加载一张图片是一件很简单的事情,但是当你需要在界面上加载一大堆图片的时候,情况就变得复杂起来. 使用图片缓存技术 在 你应用程序的UI界面加载一张图片是一件很简单的事情,但 ...
- LruCache--远程图片获取与本地缓存
Class Overview A cache that holds strong references to a limited number of values. Each time a value ...
随机推荐
- TCP/IP-TCP
Don't cry over spilt milk. "覆水难收" 参考资料:TCP/IP入门经典 (第五版) TCP/IP详解 卷一:协议 TCP是协议栈中非常重要的一个部分, ...
- 通过 Xshell 5 连接 centOS 7 服务器
一. 在安装好了centOS 7 的服务上,打开终端 运行 ip -s addr 命令 获取服务的IP地址 [root@localhost ~]# ip -s addr1: lo: <LOOPB ...
- location对象,将url解析为独立片段search属性截取传递的参数
通过location对象的search属性截取字符串传递过来的参数 search ?item=hello&name=auto&age=25 返回url中传递的参数,以?开头 funct ...
- Python新手学习基础之数据结构-序列2
长度.最大值和最小值 序列类型的数据结构,常常会用到长度检查.最大最小值检查的函数. 他们的作用: len(序列):返回列表的长度(元素个数): max(序列) :返回列表中元素最大值: min(序列 ...
- Python学习笔记四--字典与集合
字典是Python中唯一的映射类型.所谓映射即指该数据类型包含哈希值(key)和与之对应的值(value)的序列.字典是可变类型.字典中的数据是无序排列的. 4.1.1字典的创建及赋值 dict1={ ...
- MVC中的路由
authour: chenboyi updatetime: 2015-05-02 16:10:04 friendly link: 目录 1,思维导图 2,MVC处理机制简图(讲解路由解析) 3,默 ...
- Solr4.8.0源码分析(12)之Lucene的索引文件(5)
Solr4.8.0源码分析(12)之Lucene的索引文件(5) 1. 存储域数据文件(.fdt和.fdx) Solr4.8.0里面使用的fdt和fdx的格式是lucene4.1的.为了提升压缩比,S ...
- 搭了个hexo博客
上周六,气温还行,不想看书,开着电脑又想做点儿什么,于是就尝试了一把闻名已久的静态博客. 博客程序使用的是一位台湾小哥用node.js开发的hexo,传说页面生成神速.相对应的,大名鼎鼎的octopr ...
- Hadoop FileInputFormat实现原理及源码分析
FileInputFormat(org.apache.hadoop.mapreduce.lib.input.FileInputFormat)是专门针对文件类型的数据源而设计的,也是一个抽象类,它提供两 ...
- 话说python
前几年就职于一个大的软件公司时,开发过程中,有一个流程化的步骤要做,就是要由一个excel文档导出生成一堆sql语句.当时使用一个高手写的代码,只不过有限几行代码(应该不到100行),就完美实现此功能 ...