安卓快取之LruCache及設計(非同步+快取)圖片載入器LruCacheImageLoader
一、LruCache
LruCache是一套記憶體快取的解決方案,演算法基於LRU。
LRU:Least Recently Used(近期最少使用)。LruCache基於LRU演算法的快取策略。
LruCache是一個泛型類,其以強引用的方式儲存外界的快取物件。當記憶體快取達到設定的最大值時,則將記憶體快取中近期最少使用的物件移除,有效的避免了OOM的出現。
一、LruCache的基本使用
LruCache一般使用來快取圖片,下面以快取Bitmap為例
建立一個key為String型別,value為Bitmap型別的LruCache
private LruCache<String, Bitmap> mCache;
初始化LruCache,並指定LruCache的快取大小
//獲取應用程式最大可用記憶體 int maxMemory = (int) Runtime.getRuntime().maxMemory(); //指定快取大小 int cacheSize = maxMemory / 8; mCache = new LruCache<String, Bitmap>(cacheSize) { @Override protected int sizeOf(String key, Bitmap value) { //返回Bitmap的實際大小 (單位應與maxMemory一致) return value.getByteCount(); } };
獲取快取
mCache.get(key);
新增快取
mCache.put(key,value);
移除某個鍵的快取
mCache.remove(key);
清空快取
mCache.evictAll()
二、使用LruCache封裝圖片載入快取器
根據LruCache,我們可以將它封裝在LruCacheImageLoader來對圖片進行快取。設計模式為使用單例模式來設計:
在Logcat中列印非同步任務個數:
package com.cxmscb.cxm.cacheproject; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.support.v4.util.LruCache; import android.util.Log; import android.widget.ImageView; import android.widget.ListView; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import java.util.HashSet; import java.util.Set; /** * Created by cxm on 2016/8/25. */ public class LruCacheImageLoader { private LruCache<String,Bitmap> mCache; // 儲存非同步任務的集合 private Set<LruCacheAsyncTask> mTaskSet; /*ImageLoader的單例*/ private static LruCacheImageLoader mImageLoader; private Context mContext; private LruCacheImageLoader(Context context){ this.mContext = context; mTaskSet = new HashSet<>(); int maxMemory = (int) Runtime.getRuntime().maxMemory(); int cacheSize = maxMemory / 8; // 初始化LruCache mCache = new LruCache<String, Bitmap>(cacheSize){ @Override protected int sizeOf(String key, Bitmap value) { return value.getByteCount(); } }; } // 獲取LruCacheImageLoader的例項(帶同步鎖) public static LruCacheImageLoader getInstance(Context context){ if(mImageLoader==null){ synchronized (LruCacheImageLoader.class){ if(mImageLoader==null) mImageLoader = new LruCacheImageLoader(context); } } return mImageLoader; } // 根據key值獲取快取中的圖片 private Bitmap getBitmapFromMemory(String url){ return mCache.get(url); } //將一張圖片儲存到LruCache中。 private void putBitmapToMemory(String url, Bitmap bitmap) { if (getBitmapFromMemory(url) == null) { mCache.put(url, bitmap); } } /*------------以上的LruCache的使用-------------*/ /* * 對外方法:普通地載入圖片到imageView中 */ public void displayImage(ImageView iv, final String url) { //從快取中取出圖片 Bitmap bitmap = getBitmapFromMemory(url); //如果快取中沒有,先設為預設圖片 if (bitmap == null) { LruCacheAsyncTask task = new LruCacheAsyncTask(iv); task.execute(url); mTaskSet.add(task); } else { //如果快取中有 直接設定 iv.setImageBitmap(bitmap); } } /** * 對外方法:為listview載入從start到end的所有的Image * */ public void loadTagImageViewInListView(int start, int end, String[] tagUrls, ListView mListView) { Drawable.ConstantState aConstantState = mContext.getResources().getDrawable(R.drawable.loading).getConstantState(); for (int i = start; i < end; i++) { String url = tagUrls[i]; ImageView imageView = (ImageView) mListView.findViewWithTag(url); // 判斷圖片是否載入過,以免新建多個asynctask if (imageView.getDrawable().getConstantState().equals(aConstantState)) { displayImage(imageView, url); } } Log.i("num of asynctask"," "+mTaskSet.size()); } private class LruCacheAsyncTask extends AsyncTask<String,Void,Bitmap>{ private ImageView imageView; public LruCacheAsyncTask(ImageView imageView){ this.imageView = imageView; } @Override protected Bitmap doInBackground(String... strings) { Bitmap bitmap = getBitmapFromUrl(strings[0]); // 將bitmap快取到LruCache中 if(bitmap!=null){ putBitmapToMemory(strings[0],bitmap); } return bitmap; } @Override protected void onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); if (imageView != null && bitmap != null) { imageView.setImageBitmap(bitmap); } mTaskSet.remove(this); Log.i("num of asynctask"," "+mTaskSet.size()); } private Bitmap getBitmapFromUrl(String urlPath) { Bitmap bitmap = null; try { URL url = new URL(urlPath); URLConnection conn = url.openConnection(); conn.connect(); InputStream in; in = conn.getInputStream(); bitmap = BitmapFactory.decodeStream(in); // TODO Auto-generated catch block } catch (IOException e) { e.printStackTrace(); } return bitmap; } } /** * 停止所有當前正在執行的任務 */ public void cancelAllTask() { if (mTaskSet != null) { for (LruCacheAsyncTask task : mTaskSet) { task.cancel(false); } mTaskSet.clear(); Log.i("num of asynctask"," "+mTaskSet.size()); } } }
三、 使用LruCacheImageLoader來載入網路圖片:
一、專案效果圖:
首先是ListView上下滑動時不載入圖片,停止滑動才開始載入圖片
在Logcat中檢視載入圖片的非同步任務個數:
滑動時非同步任務個數為0,滑動停止時任務數為ListView中的item可見數,然後遞減,最後為0,再次滑動/停止時一直為0。主要是利用了下面的優化。
二、對ListView載入圖片的優化:
監聽ListView滾動狀態,只有當其靜止的時候才非同步載入網路圖片資料。(第一次進入也載入圖片)
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView absListView, int scrollState) {
if(scrollState==SCROLL_STATE_IDLE){
lruCacheImageLoader.loadTagImageViewInListView(mStart,mEnd,urls,listView);
}else {
// 以免產生太多無用的asynctask
lruCacheImageLoader.cancelAllTask();
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
mStart = firstVisibleItem;
mEnd = firstVisbleItem + visibleItemCount;
if(mFirstIn && visibleItemCount > 0){
lruCacheImageLoader.loadTagImageViewInListView(mStart,mEnd,urls,listView);
mFirstIn = false;
}
}
});
相關推薦
安卓快取之LruCache及設計(非同步+快取)圖片載入器LruCacheImageLoader
一、LruCache LruCache是一套記憶體快取的解決方案,演算法基於LRU。 LRU:Least Recently Used(近期最少使用)。LruCache基於LRU演算法的快取策略。 LruCache是一個泛型類,其以強引用的方式
安卓快取之DiskLruCache及設計(非同步+快取)圖片載入器DiskCacheImageLoader
DiskLruCache DiskLruCache是一套硬碟快取的解決方案,演算法同LruCache基於LRU演算法。 DiskLruCache不是由Google官方編寫的,這個類沒有被包含在Android API當中。這個類需要從網上下載
安卓實戰之登入介面設計
安卓實戰之登入介面設計 執行環境: windows10+ Android Studio2.3.3 +API 21 (適用android 5.0以上版本的手機) (1)知識儲備 (知識儲備連結:https://blog.csdn.net/biggerchong/arti
安卓sqlite之增刪改查(一)
在安卓開發中不可避免的會遇到在手機中儲存資料的時候,如果只是小量資料(如儲存設定等)的話,用SharedPreferences是個極好的選擇,它以鍵值對的形式儲存資料,但是如果資料量比較多的話,比如一個鍵對應了一個集合的情況,此時再用SharedPreferences儲存資
安卓開發之橫向滑動viewpager(可以禁用或啟用橫向滑動)
import android.content.Context; import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.view.MotionEvent; public class
安卓優化之apk瘦身(27.7M-->17.5M)
概述 apk瘦身作為優化的一部分,它的大小決定安裝的時間與佔用的記憶體,進行鍼對性的瘦身也能夠提高使用者體驗,下面就看我怎樣將一個27.7M的安裝包減肥到17.5M,足足減少了37.18%。 一、優化圖片 圖片佔用了大部分體積,所以圖片的優化首當其衝。
簡易OA漫談之工作流設計(一個Demo),完成6年前的一個貼子
6年前在騰訊做OA,那時寫了兩篇心得。 https://www.cnblogs.com/wangxiaohuo/archive/2012/08/22/2650893.html https://www.cnblogs.com/wangxiaohuo/archive/2012/08/24/2653968.ht
安卓開發入門:工具欄(Action Bar)
本文針對Android3.0及以上。主要是官方文件的翻譯加上我自己的理解。對應於官方文件的develop -- Training -- Adding the Action Bar 內容: 1.新增工具欄 2.新增工具欄按鈕 2.1 工具欄佈局 2.2新增工
安卓 Data Binding 使用方法總結(姐姐篇)
0. 前言 在專案中使用到了 Data Binding,總結使用經驗後寫成本文。 本文涉及安卓自帶框架 DataBinding 的基礎使用方法,適合初次接觸 Data Binding 的同學閱讀。 1. Data Binding 利弊 優勢 D
安卓日記——玩轉Material Design(NavigationView篇)
最近突然對Material Design感興趣,然後想看看怎麼玩。 首先要說的是NavigationView,就是我們經常要用到的側邊導航欄 在沒有NavigationView之前我們用的是普通的LinearLayout+ListView+頭部layout
iOS拼接URL,類似安卓body體進行轉碼(轉為gbk)提交。
大家都知道,AFN去提交POST的時候是不用給他拼接URL的,但是♪(^∇^*),如果說你要對這個後面的body體進行轉碼的話,如果不拼接就無法實現了,還有一個就是如果安卓那邊url的確是拼接出來的,那麼我iOS不拼接的話,只有一個結果。。。那就是請求不到資料咯! 我用一個
MySQL之新SQL優化(非同步執行)
背景 本次SQL優化是針對javaweb中的表格查詢做的。 部分網路架構圖 業務簡單說明 N個機臺將業務資料傳送至伺服器,伺服器程式將資料入庫至MySQL資料庫。伺服器中的javaweb程式將資料展示到網頁上供使用者檢視。 原資料庫設計 windows單機主從
JavaEE複習回顧十一: (基礎加強) 類載入器 && 註解 && 動態代理
參考文章: 1,動態代理——從一竅不通到恍然大悟 2,UML類圖與類的關係詳解 一,類載入器 1.1 什麼是類載入器,作用是什麼? 一個自己編寫的 Java 程式碼原始檔,起執行的過程主要分為三個階段。 第一個階段: SOURCE 級別,即原始碼階段,已
安卓開發之架構理解(MVP)
學習自MVP架構 MVP的全稱為Model-View-Presenter,即模型-檢視-協調器(主持者) Model:處理資料和業務邏輯等,如:資料庫的操作,資料的請求載入,資料運算,JavaBean; View:顯示介面,展示結果等,一切與介面相關的,如:XML檔案,
安卓佈局之表格佈局(TableLayout)
概述: Tablelayout以行和列的形式對控制元件進行管理,每一行為一個TableRow物件,或一個View控制元件。 當為TableRow物件時,可在TableRow下新增子控制元件,預設情況下,每個子控制元件佔據一列。 有多少個子控制元件就有多少列;當為View時
安卓使用POI讀取及修改Word文件(.docx格式)
說明:上一篇文章使用poi對.doc格式的word文件進行了讀取和更改,但很多情況下還需要在word文件中插入圖片,這時就需要對.docx格式的word進行操作了。 1.製作文書 文書在原始碼中可以直接看到,簡單說明一下:文書有普通欄位、表格、特定位置的圖片,又在頁首頁尾
安卓開發之多執行緒斷點下載(三)
效果圖: Log: 網上關於講解挺多的,我這裡不講解了,不懂的可以評論留言,從問題中解決問題 我可以說一下我解決問題的方式,將複雜問題劃分成多個簡單的問題 多執行緒下載一:請點選這裡 多執行緒下載二:請點選這裡 許可權: <uses
安卓IPC之aidl使用(二)---aidl本地實現
一直都以為aidl必須寫一個服務端是吧,那樣豈不是有時候需求怎麼實現,如果app的service和client屬於同一app,那樣實現是不是更好的滿足我們的需求呢。 本例子我們實現一個很簡單的例子:實現2個數相加 // ILocal.aidl pac
安卓開發之清理手機應用程式快取
清理手機應用程式快取。 拿到模組後,先實現UI介面。介面實現後開始思考整個模組要實現的功能,然後是要使用的API。 第一步:先拿到包管理器 PackageManager pm=getPackageManager(); 第二步:利用包管理器拿到所有安裝
安卓開發之自動連線藍芽2.0裝置(音響,耳機)
背景 前面的文章介紹了藍芽4.0的連線,讀寫操作等,這篇文章主要是藍芽2.0(傳統藍芽)與藍芽耳機,音響等自動連線。 許可權 和BLE一樣,藍芽2.0進行藍芽相關操作,也需要使用到藍芽許可權,在AndroidManifest.xml清單檔案中新增相應許