1. 程式人生 > >簡單實現Android圖片三級快取機制

簡單實現Android圖片三級快取機制

    使用者在使用我們的APP時,通常會重複瀏覽一些圖片,這時如果每一次瀏覽都需要通過網路獲取圖片,那麼將會非常流量。為了節省使用者流量,提高圖片載入效率,我們通常使用圖片三級快取策略,即通過網路、本地、記憶體三級快取圖片,來減少不必要的網路互動,避免浪費流量。
    網上已經有很多講述圖片三級快取的策略,這次我也來實現一次三級快取,其中用到了LRU+SoftReference關於LRU演算法,可以參考我之前的部落格LinkedHashMap最佳實踐:LruCache。首先我將整個機制流程展示給大家:

這裡寫圖片描述

下面是原始碼實現:

/**
  * @ClassName: CastielImageLoader 
  * @Description
: LRU+SoftReference * @author 猴子搬來的救兵 http://blog.csdn.net/mynameishuangshuai */
public class CastielImageLoader { private static final int MAX_CAPACITY = 20;// 連結串列長度 private static Context mContext;// 獲取APP的快取地址 private static CastielImageLoader castielImageLoader; // 鍵是圖片地址、值是軟引用 private
static final LinkedHashMap<String, SoftReference<Bitmap>> firstCacheMap = new LinkedHashMap<String, SoftReference<Bitmap>>( MAX_CAPACITY) { protected boolean removeEldestEntry(java.util.Map.Entry<String, java.lang.ref.SoftReference<Bitmap>> eldest) { // 返回true表示移除最老的軟引用,保證記憶體平衡
if (this.size() > MAX_CAPACITY) { return true; } else {// 否則往磁碟中新增 diskCache(eldest.getKey(), eldest.getValue()); return false; } } }; /** * 單例模式載入CastielImageLoader * @return */ public static CastielImageLoader getInstance() { if (castielImageLoader == null) { castielImageLoader = new CastielImageLoader(); } return castielImageLoader; } /** * 載入圖片到對應元件 * * @param key 所需載入的路徑 * @param view 被載入的元件 * @param drawable 沒有載入前預設顯示圖片 */ @SuppressWarnings("deprecation") public void loadImage(String key, ImageView view, Drawable drawable ,Context context) { mContext = context; synchronized (view) { // 檢查快取中是否已有 Bitmap bitmap = getFromCache(key); if (bitmap != null) { // 如果有了就從快取中取出顯示 view.setImageBitmap(bitmap); } else { // 軟應用快取中不存在,磁碟中也不存在,只能下載 // 下載之前應該先放一張預設圖,用來友好顯示 view.setBackgroundDrawable(drawable); // 用非同步任務去下載 new CastielAsyncImageLoaderTask(view).execute(key); } } } /** * 判斷快取中是否已經有了,如果有了就從快取中取出 * * @param key * @return */ private Bitmap getFromCache(String key) { // 檢查記憶體軟引中是否存在 synchronized (firstCacheMap) { if (firstCacheMap.get(key) != null) {// 記憶體軟引用中有 Bitmap bitmap = firstCacheMap.get(key).get(); if (bitmap != null) {// 說明拿到了 firstCacheMap.put(key, new SoftReference<Bitmap>(bitmap)); return bitmap; } } } // 檢查磁碟中是否存在 Bitmap bitmap = getFromLocalSD(key); if (bitmap != null) {// 硬碟中有 firstCacheMap.put(key, new SoftReference<Bitmap>(bitmap)); return bitmap; } return null; } /** * 判斷本地磁碟中是否已經有了該圖片,如果有了就從本地磁碟中取出 * @param key * @return */ private Bitmap getFromLocalSD(String key) { String fileName = MD5Util.getMD5Str(key); if (fileName == null) {// 如果檔名為Null,直接返回null return null; } else { String filePath = mContext.getCacheDir().getAbsolutePath() + File.separator + fileName; InputStream is = null; try { is = new FileInputStream(new File(filePath)); Bitmap bitmap = BitmapFactory.decodeStream(is); return bitmap; } catch (FileNotFoundException e) { e.printStackTrace(); } finally { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; } /** * 把圖片快取到本地磁碟,拿到圖片,寫到SD卡中 * * @param key 圖片的URL * @param value Bitmap */ private static void diskCache(String key, SoftReference<Bitmap> value) { // 把寫入SD的圖片名字改為基於MD5加密演算法加密後的名字 String fileName = MD5Util.getMD5Str(key); String filePath = mContext.getCacheDir().getAbsolutePath() + File.separator + fileName; FileOutputStream os = null; try { os = new FileOutputStream(new File(filePath)); if (value.get() != null) { value.get().compress(Bitmap.CompressFormat.JPEG, 60, os); } } catch (FileNotFoundException e) { e.printStackTrace(); } finally { if (os != null) { try { os.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * * @ClassName: MyAsyncImageLoaderTask * @Description: 非同步載入圖片 * @author */ class CastielAsyncImageLoaderTask extends AsyncTask<String, Void, Bitmap>{ private ImageView imageView;// 圖片元件 private String key;//圖片路徑 public CastielAsyncImageLoaderTask(ImageView imageView) { this.imageView = imageView; } @Override protected Bitmap doInBackground(String... params) { this.key = params[0];// 圖片的路徑 Bitmap bitmap = castielDownload(key); return bitmap; } @Override protected void onPostExecute(Bitmap result) { super.onPostExecute(result); if (result != null) {// 說明已經下載下來了 addFirstCache(key,result); imageView.setImageBitmap(result);// 載入網路中的圖片 } } } /** * 根據圖片路徑執行圖片下載 * @param key * @return */ public Bitmap castielDownload(String key) { InputStream is = null; try { is = CastielHttpUtils.castielDownLoad(key); return BitmapFactory.decodeStream(is);// InputStream這種載入方式暫用記憶體最小 } catch (IOException e) { e.printStackTrace(); } finally { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } return null; } /** * 新增到快取中去 * @param key * @param result */ public void addFirstCache(String key, Bitmap result) { if (result != null) { synchronized (firstCacheMap) { firstCacheMap.put(key, new SoftReference<Bitmap>(result)); } } } }

網路載入工具類 CastielHttpUtils.java

public class CastielHttpUtils {
    public static InputStream castielDownLoad(String key) throws IOException{
        HttpURLConnection conn = (HttpURLConnection) new URL(key).openConnection();
        return conn.getInputStream();
    }
}

測試,呼叫我們的圖片快取工具 MainActivity.java

public class MainActivity extends Activity {

    ImageView img;
    String imgURl = "http://img2.imgtn.bdimg.com/it/u=3722998253,3365379445&fm=21&gp=0.jpg";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        img = (ImageView) findViewById(R.id.img);
        CastielImageLoader.getInstance().loadImage(imgURl, img, this.getResources().getDrawable(R.drawable.ic_launcher),MainActivity.this);
    }

}

佈局檔案 activity_main

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="猴子搬來的救兵 http://blog.csdn.net/mynameishuangshuai" />

    <ImageView
        android:id="@+id/img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/tv"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="80dp"
        android:src="@drawable/tt" />

</RelativeLayout>

測試載入圖片結果如下:

這裡寫圖片描述

相關推薦

簡單實現Android圖片三級快取機制

    使用者在使用我們的APP時,通常會重複瀏覽一些圖片,這時如果每一次瀏覽都需要通過網路獲取圖片,那麼將會非常流量。為了節省使用者流量,提高圖片載入效率,我們通常使用圖片三級快取策略,即通過網路、本地、記憶體三級快取圖片,來減少不必要的網路互動,避免浪費流量

Android 圖片三級快取載入框架原理解析與程式碼實現

本文主要介紹三級快取的原理解析與實現方式。以前一直覺得三級快取圖片載入是一個很難理解的東西,但是自己看了一下午再試著寫了一遍之後感覺還是隻要沉下心思考還時很容易熟悉掌握的。 所謂三級快取:首先是記憶體-檔案(外存)-網路三級快取機制。 首先: 框架需要一個接入方法NGIm

Android 圖片三級快取

開發十年,就只剩下這套架構體系了! >>>   

關於Android開發中圖片三級快取機制

1.Android應用中聯網載入並顯示圖片時,為了使用者體驗和節省流量,一定用到圖片的快取。 2.關於三級快取的理解:記憶體快取(強引用儲存)、記憶體快取(軟引用快取)、記憶體快取(弱引用快取)、檔案快取(就是將圖片儲存為本地檔案),由此組成三級快取。 3.關於JAVA中的

Android簡單實現本地圖片和視訊選擇器功能

哈嘍,大家好,好久不見了,很久沒有更新 Android 方面的技術文章了,最近在忙公司的 AR 類的新產品,其中涉及到本地圖片和視訊的選擇和上傳功能。至於為什麼不用系統提供的圖片和視訊選擇器,原因你懂的,系統提供的選擇器只能通過 Intent 方式去獲取,這意味

圖片三級快取機制

一、什麼是三級快取? 一級: 記憶體中的快取圖片物件(Bitmap), 用Map<url, Bitmap> 二級: 手機sd卡的files或手機內部的files中快取圖片檔案(xxx.jpg/png) 三級: 伺服器端儲存圖片檔案 二、如何使用三級快取?

RecyclerView解決條目錯亂以及圖片閃越+三級快取機制

RecyclerView導致條目錯亂的原因:viewHolder的複用,一個複用的ViewHolder他裡邊的View有些屬性已經被修改了,所以新的item在使用服用的viewHolder時,那些被修改的viewHolder裡邊的屬性還依然存在,所以會導致新的item也應用

Android三級快取實現原理及LruCache 原始碼分析

介紹 oom異常:大圖片導致 圖片的三級快取:記憶體、磁碟、網路 下面通過一張圖來了解下三級快取原理: 程式碼: public class Davince { //使用固定執行緒池優化 private static Exec

某宅的Android學習筆記(二)——圖片三級快取

圖片三級快取的重要性  很多時候我們都需要從網路上下載圖片,如果在圖片很多的情況下,每次啟動app都要從網上下載,就會造成流量的浪費,影響使用者的體驗。因此,要利用快取來避免圖片的重複載入。 圖片快取方式  所謂三級快取,即: 網路快取 記憶體快取

安卓圖片三級快取策略與實現

前言: 這裡說的三級快取,分別指的是:記憶體快取、檔案快取和網路這三個層面。 一般來說,我們首次載入圖片,記憶體和檔案是沒有快取的,這樣我們需要從網路載入,載入完成後,我們會存到記憶體和檔案中去;當再次載入圖片的時候,我們會先查詢記憶體有沒有,如果有就直接顯示記憶體中的圖片

Android 中的快取機制實現

public class NewsListActivity extends Activity { private List<News> list; private ListView listView; private LoadImageAdapter adapter;//介面卡

Java簡單模擬Android中Handler-Message機制

就是 示例代碼 pri 技術分享 android ble [] handle @override 在Android中主線程與子線程的通信十分重要,Google工程師為我們提供了Handler-Message機制來解決他們之間的交互問題。今天,我們就來簡單理解Handler-

Android圖片三級緩存策略

緩存策略1.簡介 Android緩存原理都是一樣,可以自己封裝。 三級緩存: 1.內存緩存:緩存在內存中,基於LRU(least recently used )算法,機器重啟消失。 2.本地緩存。緩存在本地中。一般鍵值對形式。(url,filepath) 3.網絡緩存。從網絡加載資源,然後緩存在內

18、OpenCV Python 簡單實現一個圖片生成(類似抖音生成字母人像)

gaussian int read 。。 str gray clas range TE 1 __author__ = "WSX" 2 import cv2 as cv 3 import numpy as np 4 5 def local_threshold(i

安卓音、視頻播放功能簡單實現 --Android基礎

ket undle 顯示 perm err efault 繼續 bre mpat 1、音樂播放功能 關鍵代碼: MainActivity.java: package thonlon.example.cn.musicdemowithoutservice;import

原生js簡單實現廣告圖片彈出消失

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>首頁</title> <style> .father{

簡單實現Android視訊播放器倍速、清晰度切換、m3u8下載

簡單的前提是使用開源庫 在庫的基礎上新增相對應的功能, 以 JiaoZiVideoPlayer 為例 ,本身自帶的播放引擎是MediaPlayer,也就是Android自帶的播放器,有很多不完善的地方,倍速切換隻支援5.0以上,否則報 NoClassDefFoundError 錯誤

簡單實現一個圖片輪播

(注意要將圖片替換為你自己的圖片) public class MainActivity extends Activity { private ViewPager mViewPaper; private List<ImageView> images; private List&

[寫著玩]理解multipart/form-data,構造http表單實現android圖片上傳

關於multipart/form-data,可參考https://blog.csdn.net/zshake/article/details/77985757 客戶端  引數解釋,上傳主方法 private void submit() { Map<String, Obj

簡單實現Android頂部工具欄和底部工具欄

直接上圖,有圖有真相。 這兩個工具欄全是用佈局來實現的。 底部工具欄佈局程式碼: <?xml version="1.0" encoding="utf-8"?><RelativeLayout     ="http://schemas.androi