Android OkHttp与物理存储介质缓存:DiskLruCache(2)

本文在附录文章8,9的基础之上,把Android OkHttp与DiskLruCache相结合,综合此两项技术,实现基于OkHttp的物理存储介质缓存DiskLruCache。

用一个完整的例子加以说明。该例子的代码要实现这样的过程:代码启动后,要往一个ImageView里面加载一张网络图片,首先检查DiskLruCache是否已经存在该图片的缓存,如果存在,则直接复用缓存,如果不存在则使用OkHttp把图片异步从网络加载,当OkHttp异步加载网络图片成功后,要做两件事情:

一, 毫无疑问,要把该图片设置到目标ImageView里面。代码启动后首先要检查本地的DiskLruCache物理存储介质上是否已经有特定图片的缓存,如果有,则直接复用,不再浪费网络资源重复加载。

二,把该图片的数据写入DiskLruCache缓存中,为以后的缓存使用。此情况是当DiskLruCache不存在特定资源(本例是图片)缓存时候,要从网络加载。我使用OkHttp网络驱动加载,当OkHttp加载图片成功后,一方面要把图片设置到ImageView,另外一方面要把图片缓存到DiskLruCache以备后续使用。

完整代码:

package zhangphil.demo;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ImageView; import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.Callback; import com.jakewharton.disklrucache.DiskLruCache; public class MainActivity extends AppCompatActivity { private String TAG = "zhangphil_tag"; private String UNIQUENAME = "zhangphil_cache"; private DiskLruCache mDiskLruCache = null; //缓存大小
private int DISK_CACHE_MAX_SIZE = 10 * 1024 * 1024; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); //初始化DiskLruCache
makeDiskLruCache(); //在布局里面放一个ImageView,放网络请求后的图片
final ImageView image = (ImageView) findViewById(R.id.imageView); //我的博客头像
String image_url = "http://avatar.csdn.net/9/7/A/1_zhangphil.jpg"; Bitmap bmp = readBitmapFromDiskLruCache(image_url); //首先检查DiskLruCache是否已经缓存了特定资源,如果有则直接复用。
//如果没有则从网路加载。
if (bmp != null) {
image.setImageBitmap(bmp);
} else {
downloadBitmapFromNetwork(image, image_url);
}
} //从DiskLruCache中读取缓存
private Bitmap readBitmapFromDiskLruCache(String url) {
DiskLruCache.Snapshot snapShot = null;
try {
//把url转换成一个md5字符串,然后以这个md5字符串作为key
String key = urlToKey(url); snapShot = mDiskLruCache.get(key);
} catch (Exception e) {
e.printStackTrace();
} if (snapShot != null) {
Log.d(TAG, "发现缓存:" + url);
InputStream is = snapShot.getInputStream(0);
Bitmap bitmap = BitmapFactory.decodeStream(is);
Log.d(TAG, "从缓存中读取Bitmap."); return bitmap;
} else
return null;
} //把byte字节写入缓存DiskLruCache
private void writeToDiskLruCache(String url, byte[] buf) throws Exception {
Log.d(TAG, url + " : 开始写入缓存..."); //DiskLruCache缓存需要一个key,我先把url转换成md5字符串,
//然后以md5字符串作为key键
String key = urlToKey(url);
DiskLruCache.Editor editor = mDiskLruCache.edit(key); OutputStream os = editor.newOutputStream(0);
os.write(buf);
os.flush();
editor.commit(); mDiskLruCache.flush(); Log.d(TAG, url + " : 写入缓存完成.");
} private void makeDiskLruCache() {
try {
File cacheDir = getDiskCacheDir(this, UNIQUENAME); if (!cacheDir.exists()) {
Log.d(TAG, "缓存目录不存在,创建之...");
cacheDir.mkdirs();
} else
Log.d(TAG, "缓存目录已存在,不需创建."); //第二个参数我选取APP的版本code。DiskLruCache如果发现第二个参数version不同则销毁缓存
//第三个参数为1,在写缓存的流时候,newOutputStream(0),0为索引,类似数组的下标
mDiskLruCache = DiskLruCache.open(cacheDir, getVersionCode(this), 1, DISK_CACHE_MAX_SIZE);
} catch (Exception e) {
e.printStackTrace();
}
} private void downloadBitmapFromNetwork(final ImageView image, final String image_url) {
Log.d(TAG, "从网络中加载图片资源 ... @ " + image_url); //初始化OkHttpClient
final OkHttpClient client = new OkHttpClient(); //创建OkHttpClient针对某个url的数据请求
Request request = new Request.Builder().url(image_url).build(); Call call = client.newCall(request); //请求加入队列
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//此处处理请求失败的业务逻辑
} @Override
public void onResponse(Call call, Response response) throws IOException {
//如果response响应成功则继续,否则返回
if (!response.isSuccessful())
return; //我写的这个例子是请求一个图片
//response的body是图片的byte字节
byte[] bytes = response.body().bytes(); //已经获得图片数据,记到要写入硬盘缓存
//出于性能考虑,此处可以放到后台或者放到一个线程里面处理
//简单期间,我就在这儿直接写缓存了。
try {
writeToDiskLruCache(image_url, bytes);
} catch (Exception e) {
e.printStackTrace();
} //把byte字节组装成图片
final Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); //回调是运行在非ui主线程,
//数据请求成功后,在主线程中更新
runOnUiThread(new Runnable() {
@Override
public void run() {
//网络图片请求成功,更新到主线程的ImageView
image.setImageBitmap(bmp);
}
});
}
});
} /*
*
* 当SD卡存在或者SD卡不可被移除的时候,就调用getExternalCacheDir()方法来获取缓存路径,
* 否则就调用getCacheDir()方法来获取缓存路径。
* 前者获取到的就是 /sdcard/Android/data/<application package>/cache
* 而后者获取到的是 /data/data/<application package>/cache 。
*
* */
public File getDiskCacheDir(Context context, String uniqueName) {
String cachePath = null;
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || !Environment.isExternalStorageRemovable()) {
cachePath = context.getExternalCacheDir().getPath();
} else {
cachePath = context.getCacheDir().getPath();
} File dir = new File(cachePath + File.separator + uniqueName);
Log.d(TAG, "缓存目录:" + dir.getAbsolutePath()); return dir;
} //版本名
public static String getVersionName(Context context) {
return getPackageInfo(context).versionName;
} //版本号
public static int getVersionCode(Context context) {
return getPackageInfo(context).versionCode;
} private static PackageInfo getPackageInfo(Context context) {
PackageInfo pi = null; try {
PackageManager pm = context.getPackageManager();
pi = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_CONFIGURATIONS); return pi;
} catch (Exception e) {
e.printStackTrace();
} return pi;
} public static String urlToKey(String url) {
return getMD5(url);
} /*
* 传入一个字符串String msg,返回Java MD5加密后的16进制的字符串结果。
* 结果形如:c0e84e870874dd37ed0d164c7986f03a
*/
public static String getMD5(String msg) {
MessageDigest md = null;
try {
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
md.reset();
md.update(msg.getBytes());
byte[] bytes = md.digest(); String result = "";
for (byte b : bytes) {
// byte转换成16进制
result += String.format("%02x", b);
} return result;
}
}

涉及到网络和读写存储,不要忘记加权限:

 <!-- SDCard中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 向SDCard写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.INTERNET"></uses-permission>

附录文章:

1,《Android第三方异步网路加载库AsyncHttpClient内部实现缓存策略了吗?》链接:http://blog.csdn.net/zhangphil/article/details/48595817 


2,《Android图片加载与缓存开源框架:Android Glide》链接:http://blog.csdn.net/zhangphil/article/details/45535693


3,《Android获取App版本号和版本名》链接:http://blog.csdn.net/zhangphil/article/details/43795099


4,《基于Java LinkedList,实现Android大数据缓存策略》链接:http://blog.csdn.net/zhangphil/article/details/44116885


5,《使用新式LruCache取代SoftReference缓存图片,Android异步加载图片》链接:http://blog.csdn.net/zhangphil/article/details/43667415


6,《使用Android新式LruCache缓存图片,基于线程池异步加载图片》链接:http://blog.csdn.net/zhangphil/article/details/44082287


7,《Java MD5(字符串)》链接:http://blog.csdn.net/zhangphil/article/details/44152077


8,《Android OkHttp(1)》链接:http://blog.csdn.net/zhangphil/article/details/51861503


9,《Android二级缓存之物理存储介质上的缓存DiskLruCache》链接:http://blog.csdn.net/zhangphil/article/details/51888974

Android OkHttp与物理存储介质缓存:DiskLruCache(2)的更多相关文章

  1. Android okHttp网络请求之缓存控制Cache-Control

    前言: 前面的学习基本上已经可以完成开发需求了,但是在项目中有时会遇到对请求做个缓存,当没网络的时候优先加载本地缓存,基于这个需求我们来学习一直okHttp的Cache-Control. okHttp ...

  2. Android okHttp网络请求之Json解析

    前言: 前面两篇文章介绍了基于okHttp的post.get请求,以及文件的上传下载,今天主要介绍一下如何和Json解析一起使用?如何才能提高开发效率? okHttp相关文章地址: Android o ...

  3. Android okHttp网络请求之Get/Post请求

    前言: 之前项目中一直使用的Xutils开源框架,从xutils 2.1.5版本使用到最近的xutils 3.0,使用起来也是蛮方便的,只不过最近想着完善一下app中使用的开源框架,由于Xutils里 ...

  4. Android okHttp网络请求之文件上传下载

    前言: 前面介绍了基于okHttp的get.post基本使用(http://www.cnblogs.com/whoislcj/p/5526431.html),今天来实现一下基于okHttp的文件上传. ...

  5. Android okHttp网络请求之Retrofit+Okhttp+RxJava组合

    前言: 通过上面的学习,我们不难发现单纯使用okHttp来作为网络库还是多多少少有那么一点点不太方便,而且还需自己来管理接口,对于接口的使用的是哪种请求方式也不能一目了然,出于这个目的接下来学习一下R ...

  6. Android二级缓存之物理存储介质上的缓存DiskLruCache

     Android二级缓存之物理存储介质上的缓存DiskLruCache Android DiskLruCache属于物理性质的缓存,相较于LruCache缓存,则DiskLruCache属于And ...

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

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

  8. Android内存优化之磁盘缓存

    前言: 在上一篇文章中介绍了内存缓存,内存缓存的优点就是很快,但是它又有缺点: 空间小,内存缓存不可能很大: 内存紧张时可能被清除: 在应用退出时就会消失,做不到离线: 基于以上的缺点有时候又需要另外 ...

  9. Android OkHttp(1)

     Android OkHttp(1) OkHttp是一个流行的第三方开源网络请求框架,在目前的一些APP开发中比较流行.Android平台开源的网络请求框架不少,比如常见的Volley, Asyn ...

随机推荐

  1. QT5每日一学(一)下载与安装

    一.Qt SDK的下载和安装 1.下载        Qt官网主页提供了最新版Qt的下载,不过我们更倾向于去资源下载页面(https://download.qt.io/official_release ...

  2. 逆序数 UVALive 6508 Permutation Graphs

    题目传送门 /* 题意:给了两行的数字,相同的数字连线,问中间交点的个数 逆序数:第一行保存每个数字的位置,第二行保存该数字在第一行的位置,接下来就是对它求逆序数 用归并排序或线段树求.想到了就简单了 ...

  3. B/S和C/S示意图

    B/S C/S

  4. Web自动化测试框架-PO模式

    Web自动化测试框架(WebTestFramework)是基于Selenium框架且采用PageObject设计模式进行二次开发形成的框架. 一.适用范围:传统Web功能自动化测试.H5功能自动化测试 ...

  5. Android开发学习——Volley框架

    转载至: http://blog.csdn.net/guolin_blog/article/details/17482095 一些概念性的东西 大家进入上边链接理解,我贴一下 具体的实现代码: pub ...

  6. CF599B Spongebob and Joke

    思路: 模拟,注意特判. 实现: #include <iostream> #include <cstdio> using namespace std; ], x[], y[], ...

  7. 浏览器和ES5的介绍

    浏览器的组成 : shell(浏览器的外壳).内核(渲染引擎.js引擎)主流浏览器及其内核: IE                    tritent(IE9及以下,IE10及以上用webkit) ...

  8. DeltaFish 选题报告总结

    选题结果:校园物资流动系统 报告地点:3A101 会议时间:16:00 ~ 18:00 与会人员:软工小组全体成员 请假人员:无  缺席人员:无 报告人:陈志锴 一.报告内容总结 1.产品功能 针对校 ...

  9. 最近面试oracle 数据库的知识点

    1. Oracle跟SQL Server 2005的区别? 宏观上: 1). 最大的区别在于平台,oracle可以运行在不同的平台上,sql server只能运行在windows平台上,由于windo ...

  10. vba,excel,网址提取名字与链接url

    '宏操作 Sub 复制超级链接() '这里控制读取A列的第1到10行,你根据自已的要求修改一下起始和结束行数 ).Hyperlinks.Count > ).Value = Cells(a, ). ...