版权声明:本文为HaiyuKing原创文章,转载请注明出处!
前言
内存缓存LruCache和磁盘缓存DiskLruCache的封装类,主要用于图片缓存。
效果图
代码分析
内存缓存LruCache和磁盘缓存DiskLruCache根据实际情况进行缓存,有时候需要两者都用到,有时候只用磁盘缓存即可。
使用步骤
一、项目组织结构图
注意事项:
1、 导入类文件后需要change包名以及重新import R文件路径
2、 Values目录下的文件(strings.xml、dimens.xml、colors.xml等),如果项目中存在,则复制里面的内容,不要整个覆盖
二、导入步骤
将Cache、DiskLruCache文件复制到项目中
在AndroidManifest.xml中添加权限
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.why.project.cachedemo"> <!-- =====================Cache【硬盘缓存工具类(包含内存缓存LruCache和磁盘缓存DiskLruCache)】======================= --> <!-- 允许程序打开网络套接字 --> <uses-permission android:name="android.permission.INTERNET"/> <!-- 允许程序访问有关GSM网络信息 --> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- 允许程序访问Wi-Fi网络状态信息 --> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <!-- 在SD卡中创建与删除文件权限 --> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> <!-- 允许程序读取外部存储文件 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <!-- 允许程序写入外部存储,如SD卡上写文件 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest>
添加运行时权限的处理(本demo中采用的是修改targetSDKVersion=22)
三、使用方法
package com.why.project.cachedemo; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; import com.why.project.cachedemo.utils.cache.Cache; import java.net.URL; public class MainActivity extends AppCompatActivity { private Button btn_save; private Button btn_show; private Button btn_getsize; private Button btn_remove; private TextView tv_size; private ImageView img_show; private GetImgToSaveCacheTask getImgToSaveCacheTask;//获取图片并保存到缓存的异步请求类 /**内存、磁盘缓存*/ private Cache mCache; String imgUrl = "http://img.ithome.com/newsuploadfiles/2014/12/20141223_115629_592.jpg"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); /**必须在使用之前初始化*/ mCache = new Cache(this); mCache.initMemoryCache(); mCache.initDiskCache(); initViews(); initEvents(); } @Override public void onPause() { super.onPause(); //cancel方法只是将对应的AsyncTask标记为cancel状态,并不是真正的取消线程的执行,在Java中并不能粗暴的停止线程,只能等线程执行完之后做后面的操作 if(getImgToSaveCacheTask != null && getImgToSaveCacheTask.getStatus() == AsyncTask.Status.RUNNING){ getImgToSaveCacheTask.cancel(true); } mCache.clearCache(); System.gc(); } private void initViews() { btn_save = (Button) findViewById(R.id.btn_save); btn_show = (Button) findViewById(R.id.btn_show); btn_getsize = (Button) findViewById(R.id.btn_getsize); btn_remove = (Button) findViewById(R.id.btn_remove); tv_size = (TextView) findViewById(R.id.tv_size); img_show = (ImageView) findViewById(R.id.img_show); } private void initEvents() { btn_save.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { saveToCache(imgUrl); } }); btn_show.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { showImg(imgUrl); } }); btn_getsize.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String cacheSize = mCache.getSize(); tv_size.setText(tv_size.getText() + cacheSize); } }); btn_remove.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mCache.removeFromCache(mCache.hashKeyForDisk(imgUrl)); } }); } /**显示图片*/ private void showImg(String imgUrl) { String cacheKey = mCache.hashKeyForDisk(imgUrl); Bitmap bitmap = mCache.getBitmapFromCache(cacheKey);//从缓存中获取图片bitmap if(bitmap != null){ BitmapDrawable drawable = null; Resources resources = getResources(); drawable = new BitmapDrawable(resources, bitmap); //设置背景图片 if(Build.VERSION.SDK_INT >= 16) { img_show.setBackground(drawable); }else{ img_show.setBackgroundDrawable(drawable); } } } /**保存图标到缓存中*/ private void saveToCache(String imgUrl){ //如果已经下载过来,那么不需要重新下载 String cacheKey = mCache.hashKeyForDisk(imgUrl); Bitmap bitmap = mCache.getBitmapFromCache(cacheKey);//从缓存中获取图片bitmap if(bitmap == null){ //判断是否有网络,此处注释掉 //if (HttpUtil.isNetworkAvailable(MainActivity.this)) { //执行异步任务 GetImgToSaveCacheTask getImgTask = new GetImgToSaveCacheTask(); getImgTask.execute(imgUrl); /*} else { this.showShortToast(getResources().getString(R.string.httpError)); }*/ } } /** * 保存图标异步请求类 */ public class GetImgToSaveCacheTask extends AsyncTask<String, Void, String> { @Override protected void onPreExecute() { //showProgressDialog("");//显示加载对话框 } @Override protected String doInBackground(String... params) { String data = ""; if(! isCancelled()){ try { if(params[0].equals("")){ data = ""; }else{ //下载图片并缓存 BitmapFactory.Options opts = new BitmapFactory.Options(); String cacheKey = mCache.hashKeyForDisk(params[0]); Bitmap bitmap = null; synchronized(mCache.mDiskCacheLock){ if(mCache.getBitmapFromCache(cacheKey) == null) { //如果缓存中无图片,则添加到磁盘缓存和内存缓存中 bitmap = BitmapFactory.decodeStream(new URL(params[0]).openConnection().getInputStream(), null, opts); mCache.addBitmapToMemoryCache(cacheKey, bitmap); mCache.addBitmapToDiskCache(cacheKey, bitmap); } else if(mCache.mMemoryCache.get(cacheKey) == null) { //如果内存缓存中无图片,则磁盘缓存中添加到内存缓存中 bitmap = mCache.getBitmapFromDiskCache(cacheKey); mCache.addBitmapToMemoryCache(cacheKey, bitmap); } else if(mCache.getBitmapFromDiskCache(cacheKey) == null) { //如果磁盘缓存中无图片,则从内存缓存中添加到磁盘缓存中 bitmap = mCache.getBitmapFromMemCache(cacheKey); mCache.addBitmapToDiskCache(cacheKey, bitmap); } } data = "success"; } } catch (Exception e) { e.printStackTrace(); } } return data; } @Override protected void onPostExecute(String result) { super.onPostExecute(result); if(isCancelled()){ return; } try { if (result != null && !"".equals(result)){ //缓存成功,此处可以进行其他处理,比如显示图片 } } catch (Exception e) { e.printStackTrace(); } finally { if(! isCancelled()){ //dismissProgressDialog();//隐藏加载对话框 } } } } }
注意:
- 缓存图片建议使用异步请求,demo中使用的是AsyncTask方式;
- 异步请求缓存图片之前需要先进行网络判断,请参考HttpUtil 【判断网络连接的封装类】
缓存目录示意图:
混淆配置
无
参考资料
Android DiskLruCache完全解析,硬盘缓存的最佳方案