综合使用LruCache和DiskLruCache 缓存图片
Activity
public class MainActivity extends Activity { private GridView mPhotoWall; private PhotoWallAdapter mAdapter; @Override protected 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); } @Override protected void onPause() { super.onPause(); mAdapter.fluchCache();//将内存中的操作记录同步到日志文件journal当中,在Activity的onPause()方法中去调用一次flush()方法就可以了 } @Override protected 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/8 int cacheSize = maxMemory / 8; mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { @Override protected 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") @Override public 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; } @Override public int getCount() { return urls == null ? 0 : urls.length; } @Override public Object getItem(int position) { return urls == null ? null : urls[position]; } @Override public 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; @Override protected Bitmap doInBackground(String... params) { imageUrl = params[0]; FileDescriptor fileDescriptor = null;//与此流有关的文件描述符对象,主要实际用途是创建一个包含该结构的 FileInputStream 或 FileOutputStream Snapshot snapShot = null; FileInputStream fileInputStream = null;//缓存文件的输入流 try { // 首先根据图片的URL生成对应的MD5 final 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; } @Override protected 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-sdk android:minSdkVersion="14" android:targetSdkVersion="17" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android: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 ...
随机推荐
- Static Class (静态类)
一般情况下是不可以用static修饰类的.如果一定要用static修饰类的话,通常static修饰的是匿名内部类. 在一个类中创建另外一个类,叫做成员内部类.这个成员内部类可以静态的(利用static ...
- 开始编写正式的iOS 程序(iOS编程指导)
App设计基础 在确定了你的App主要功能后,需要把它转化为代码.如果你是第一次开发属于自己的iOS App,需要花些时间熟悉基本概念.iOS内置了很多设计样式,多了解下能对你以后有帮助. 初稿 设计 ...
- gearmand的安装
1.安装gperf libuuid-devel yum install -y gperf libuuid-devel 2.安装 libevent yum install libevent libeve ...
- IOS开发之UIScrollView
一.UIScrollView的边界处理问题: bounds属性: (1)当bounces属性设置为YES时,当UIScrollView中图片滑动到边界的时候会出现弹动的效果,就像是Linux中的果冻效 ...
- JavaScript-学习一获取表单的值
<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>he ...
- [HTML5 Canvas学习] 基础知识
HTML5 canvas元素通过脚本语言(通常是Javascript) 绘制图形, 它仅仅是一个绘图环境,需要通过getContext('2d')方法获得绘图环境对象,使用绘图环境对象在canvas元 ...
- text-overflow:ellipsis 的应用(转载)
关键字: text-overflow:ellipsis 语法:text-overflow : clip | ellipsis 取值: clip :默认值 .不显示省略标记(...),而是简单的裁切. ...
- Hibernate的批量处理
Hibernate完全以面向对象的方式操作数据库,当程序员以面向对象的方式操作持久化对象时,将自动转换为对数据的操作.例如我们Session的delete()方法,来删除持久化对象,Hibernate ...
- 转:视觉中国的NoSQL之路:从MySQL到MongoDB
起因 视觉中国网站(www.chinavisual.com)是国内最大的创意人群的专业网站.2009年以前,同很多公司一样,我们的CMS和社区产品都构建于PHP+Nginx+MySQL之上:MySQL ...
- LED驅動芯片 兩種恒流控制方式
下面要說的是,兩種恒流控制模式的開關電源,從而產生兩種做法.這兩種做法無論是原理,還是器件應用,還是性能差別,相當都較大. 首先說原理.第一種以現在恒流型LED專用IC為代表,主要如9910系 ...