Android三级缓存机制工具类的实现
一.三級緩存概述
(一)三級緩存的三級
第一級是內存,最快,不需要網絡
第二級是本地,不需要網絡
第三級是網絡,需要網絡請求
??????三級緩存機制的思想:
??????如果在內存中獲取到數據,就不去本地和網絡中獲取。
??????如果在本地中獲取到數據就不去網絡中獲取,
??????如果內存和本地中不存在數據,就要去網絡中請求數據
??????三級緩存技術能有效節省用戶的流量,但是也會增加一些內存負擔。
二.使用示例展示三級緩存工具欄類的使用
??????程序運行后的頁面:
??????雖然只用一個按鈕和一個圖片顯示,但是通過測試(聯網狀態和斷網狀態對比)能知道圖片是從網絡中獲取還是從本地或者中內存。
??????這里用到了幾個其他自己編程的小工具類。
(一)添加手機權限,網絡權限和SD卡寫的權限
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />(二)編寫布局文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:id="@+id/activity_main"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><Button android:layout_width="match_parent"android:layout_height="wrap_content"android:onClick="start"android:text="加載圖片" /><ImageView android:id="@+id/main_iv"android:layout_width="match_parent"android:layout_height="wrap_content"/></LinearLayout>上面是一個非常簡單的布局文件。
(三)設計一個方便調試顯示個工具類
package com.lwz.threelevelt;import android.content.Context; import android.util.Log; import android.widget.Toast;/*** 本類用于簡易的顯示信息* 比如土司,或Log信息*/public class ShowUtils {//這里DEBUG的作用是,可以在程序完成后設置DEBUG的值為false,程序以后就不會在顯示以前的打印信息public static boolean DEBUG = true;//各種Log打印public static void e(Object o) {if (DEBUG)Log.e("TAG", "打印:------ " + o.toString());}public static void e(int i) {if (DEBUG)Log.e("TAG", "打印:------ " + i);}public static void e(float i) {if (DEBUG)Log.e("TAG", "打印:------ " + i);}public static void e(boolean b) {if (DEBUG)Log.e("TAG", "打印:------ " + b);}//各種土司public static void ts(Context context, Object object) {if (DEBUG)Toast.makeText(context, object + "", Toast.LENGTH_SHORT).show();}public static void tsl(Context context, Object object) {if (DEBUG)Toast.makeText(context, object + "", Toast.LENGTH_LONG).show();}}(四)文件操作的一個工具類
public class FileUtils {//判斷是否本地有sd卡,確定是否保存在SD卡內String path;//文件存儲的地方/*** 通過構造方法傳入存儲的路徑*/public FileUtils(Context context, String dirName) {//判斷是否本地有sd卡,這里代表的是SD卡在就緒的狀態 //這里判斷相等狀態要使用.equal,使用==會匹配不到???if (Environment.getExternalStorageState() .equal( Environment.MEDIA_MOUNTED)) {ShowUtils.e("SD卡就緒狀態");path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + dirName;} else {ShowUtils.e("SD卡沒有就緒狀態");//保存在內部存儲器中path = context.getCacheDir().getAbsolutePath() + "/" + dirName;}//創建文件new File(path).mkdirs();}/*** 文件的寫入* 傳入一個文件的名稱和一個Bitmap對象* 最后的結果是保存一個圖片*/public void saveToSDCard(String key, Bitmap bmp) {FileOutputStream fos = null;try {fos = new FileOutputStream(new File(path, key));} catch (FileNotFoundException e) {e.printStackTrace();}//保存圖片的設置bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);try {fos.close();//關閉流} catch (IOException e) {e.printStackTrace();}}/*** 文件的讀取,* 根據文件的名字,讀取出一個Bitmap的對象,* 如果之前保存過就有值,否則是null*/public Bitmap readFromSDCard(String key) {return BitmapFactory.decodeFile(new File(path, key).getAbsolutePath()); } }(五)最最重要的三級緩存功能的實現的工具類
package com.lwz.threelevelt;import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Handler; import android.os.Message; import android.support.annotation.NonNull; import android.support.v4.util.LruCache;import java.io.InputStream; import java.net.URL; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;import static com.lwz.threelevelt.ShowUtils.e;/*** 圖片三級緩存機制的實現類* <p>* 首先是內存,最快* 其次是本地,不需要網絡* 最后是網絡,需要網絡請求* 這如果在內存中獲取到數據,就不去本地和網絡中獲取,同樣如果在本地中獲取到數據就不去網絡中獲取,* 如果內存和本地中不存在數據,采取網絡中請求數據* <p>* ,這里結合的是另一個fileUtils的工具類來實現* <p>* 調用方法也是很簡單的:*/public class ImageLoader {//下載使用的線程池對象ExecutorService threadLooper;//緩存類,能過獲取和寫入數據到緩存中,短時間的存儲!!private static LruCache<String, Bitmap> cache;//文件操作類對象private FileUtils fileUtils;/*** 構造方法,需要傳入一個保存文件的名字* 實例化:線程池對象,緩存類,文件操作類對象*/public ImageLoader(Context context, String dirName) {//獲取系統分配的最大內存int maxSize = (int) (Runtime.getRuntime().maxMemory() / 8);//實例化緩存類的對象cache = new LruCache<String, Bitmap>(maxSize) {//每一個鍵所對應的值的大小//自動釋放低頻率的文件@Overrideprotected int sizeOf(String key, Bitmap value) {return value.getByteCount();}};fileUtils = new FileUtils(context, dirName);//實例化文件操作類的對象threadLooper = Executors.newFixedThreadPool(5);//實例化線程池,并設置運行的最大線程數}/*** 下載圖片的方法,這也是提供給我們調用的方法* 需要傳入一個URL地址,和一個圖片下載成功后的回調方法*/public void loadImage(final String url, @NonNull final ImageLoadListener listener) {//去掉所有需要轉義的斜杠,把獲得的字符串作為Bitmap對象的一個標示符,通過它和它的Bitmap對象一一對應final String key = url.replaceAll("[\\W]", "");//第一級,先判斷緩存類中是否有數據if (readFromCache(key) != null) {//直接拿出來e("從緩存中加載");listener.loadImage(readFromCache(key));} else {//第二級,再判斷本地中是否存在數據final Bitmap bitmap = fileUtils.readFromSDCard(key);//查看是否存在數據if (bitmap != null) {//本地中存在數據//存儲到緩存e("從SDCard中加載");saveToCache(key, bitmap);//把從SD卡中讀取到的數據保存到緩存中,//返回listener.loadImage(fileUtils.readFromSDCard(key));//返回一個數據給調用者} else {//第三級,從網絡中下載數據//要把數據分別存入本地中內存中//下載,使用子線程//創建一個Handler對象,這里還是主線程,// 下載是在子線程,然后調用Handler對象發送數據給主線程final Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);e("從網絡下載");listener.loadImage((Bitmap) msg.obj);}};//線程池的使用,在里面下載數據threadLooper.execute(new Runnable() {@Overridepublic void run() {//開始下載try {URL u = new URL(url);InputStream inputStream = u.openStream();Bitmap bitmap1 = BitmapFactory.decodeStream(inputStream);//獲取bitmap對象fileUtils.saveToSDCard(key, bitmap1);//保存文件到SD卡saveToCache(key, bitmap1);//保存文件到內存中//使用Handler對象給主線程發送消息Message msg = handler.obtainMessage();msg.obj = bitmap1;handler.sendMessage(msg);} catch (Exception e) {e.printStackTrace();}}});}}}/*** 取消子線程的任務*/public void cancelDownLoad() {threadLooper.shutdown();}/*** 定義一個接口,里面有一個方法,* 這里有一個Bitmap對象參數,作用是讓調用這接收這個Bitmap對象,實際這bitmap對象就是緩存中的對象*/public interface ImageLoadListener {public void loadImage(Bitmap bmp);}/*** 使用緩存類存儲Bitmap對象*/private void saveToCache(String key, Bitmap bmp) {cache.put(key, bmp);}/*** 使用緩存類獲取Bitmap對象*/private Bitmap readFromCache(String key) {return cache.get(key);} }??????上面代碼中e(“XXX”) 和ShowUtils.e(“XXX”)效果是一樣的,因為導入方式是靜態的:import static com.lwz.threelevelt.ShowUtils.e;所以可以省略類名ShowUtils。
??????有些簡單的方法這樣使用是非常方便的。
(六)最后的調用類
package com.lwz.threelevelt;import android.graphics.Bitmap; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.ImageView;/*** 三級緩存工具類的調用測試* 1.創建三級緩存類的對象,傳入上下文和圖片名字* 2.調用三級緩存類的對象的loadImage方法,* 傳入兩個參數,第一個參數是URL地址,第二個參數是回調接口,在回調接口內可以接收到根據URL地址下載到的Bitmap對象*/ public class MainActivity extends AppCompatActivity {//定義布局的控件ImageView imageView;//定義三級緩存工具類ImageLoader loader;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);ShowUtils.DEBUG = false;setContentView(R.layout.activity_main);imageView = (ImageView) findViewById(R.id.main_iv);loader = new ImageLoader(this, "test3");//創建文件夾}public void start(View v) {loader.loadImage("http://p3.so.qhmsg.com/bdr/326__/t018da60b972e086a1d.jpg", new ImageLoader.ImageLoadListener() {@Overridepublic void loadImage(Bitmap bmp) {imageView.setImageBitmap(bmp);}});} }??????可以看到實現了三級緩存的工具類后,調用還是非常簡單的。
??????程序運行后顯示的界面:
第一次點擊按鈕,頁面顯示:
顯示的Log數據:
可以看到數據是從網絡中獲取到的。因為剛剛開始本地或緩存中都沒有數據。
第二次或多次點擊按鈕,顯示的Log數據:
可以看到數據是從緩存中獲取到的。因為圖片的數據每次打開后,緩存中都會有它的數據。
退出程序后,再進入程序點擊按鈕,顯示的Log數據:
可以看到數據是從本地中獲取到的。因為緩存中的數據很容易被回收,本地的數據不會被回收。
卸載程序后,再安裝程序點擊按鈕,顯示的Log數據:
??????可以看到數據是從SD卡中獲取到的。因為程序存放的數據是在SD卡下的,程序卸載后數據依然存在,但是如果數據保存在內部存儲器,卸載程序也會刪除數據。
??????上面就是三級緩存圖片工具類的實現和三級緩存圖片的一個簡單使用。
總結
以上是生活随笔為你收集整理的Android三级缓存机制工具类的实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 〖全域运营实战白宝书 - 运营角色认知篇
- 下一篇: 三代组装软件miniasm笔记