詳解Android 圖片的三級緩存及圖片壓縮
為什么需要圖片緩存
Android默認(rèn)給每個應(yīng)用只分配16M的內(nèi)存,所以如果加載過多的圖片,為了防止內(nèi)存溢出,應(yīng)該將圖片緩存起來。圖片的三級緩存分別是:
- 內(nèi)存緩存
- 本地緩存
- 網(wǎng)絡(luò)緩存
其中,內(nèi)存緩存應(yīng)優(yōu)先加載,它速度最快;本地緩存次優(yōu)先加載,它速度也快;網(wǎng)絡(luò)緩存不應(yīng)該優(yōu)先加載,它走網(wǎng)絡(luò),速度慢且耗流量。
三級緩存的具體實(shí)現(xiàn)
網(wǎng)絡(luò)緩存
- 根據(jù)圖片的url去加載圖片
- 在本地和內(nèi)存中緩存
public class NetCacheUtils {
private LocalCacheUtils mLocalCacheUtils;
private MemoryCacheUtils mMemoryCacheUtils;
public NetCacheUtils(LocalCacheUtils localCacheUtils,
MemoryCacheUtils memoryCacheUtils) {
mLocalCacheUtils = localCacheUtils;
mMemoryCacheUtils = memoryCacheUtils;
}
/**
* 從網(wǎng)絡(luò)下載圖片
*
* @param ivPic
* @param url
*/
public void getBitmapFromNet(ImageView ivPic, String url) {
new BitmapTask().execute(ivPic, url);// 啟動AsyncTask,
// 參數(shù)會在doInbackground中獲取
}
/**
* Handler和線程池的封裝
*
* 第一個泛型: 參數(shù)類型 第二個泛型: 更新進(jìn)度的泛型, 第三個泛型是onPostExecute的返回結(jié)果
*
*
*/
class BitmapTask extends AsyncTask<Object, Void, Bitmap> {
private ImageView ivPic;
private String url;
/**
* 后臺耗時方法在此執(zhí)行, 子線程
*/
@Override
protected Bitmap doInBackground(Object... params) {
ivPic = (ImageView) params[0];
url = (String) params[1];
ivPic.setTag(url);// 將url和imageview綁定
return downloadBitmap(url);
}
/**
* 更新進(jìn)度, 主線程
*/
@Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
/**
* 耗時方法結(jié)束后,執(zhí)行該方法, 主線程
*/
@Override
protected void onPostExecute(Bitmap result) {
if (result != null) {
String bindUrl = (String) ivPic.getTag();
if (url.equals(bindUrl)) {// 確保圖片設(shè)定給了正確的imageview
ivPic.setImageBitmap(result);
mLocalCacheUtils.setBitmapToLocal(url, result);// 將圖片保存在本地
mMemoryCacheUtils.setBitmapToMemory(url, result);// 將圖片保存在內(nèi)存
System.out.println("從網(wǎng)絡(luò)緩存讀取圖片啦...");
}
}
}
}
/**
* 下載圖片
*
* @param url
* @return
*/
private Bitmap downloadBitmap(String url) {
HttpURLConnection conn = null;
try {
conn = (HttpURLConnection) new URL(url).openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
conn.setRequestMethod("GET");
conn.connect();
int responseCode = conn.getResponseCode();
if (responseCode == 200) {
InputStream inputStream = conn.getInputStream();
//圖片壓縮處理
BitmapFactory.Options option = new BitmapFactory.Options();
option.inSampleSize = 2;//寬高都壓縮為原來的二分之一, 此參數(shù)需要根據(jù)圖片要展示的大小來確定
option.inPreferredConfig = Bitmap.Config.RGB_565;//設(shè)置圖片格式
Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, option);
return bitmap;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
conn.disconnect();
}
return null;
}
}
本地緩存
兩個方法:設(shè)置本地緩存,獲取本地緩存
public class LocalCacheUtils {
public static final String CACHE_PATH = Environment
.getExternalStorageDirectory().getAbsolutePath() + "/local_cache";
/**
* 從本地sdcard讀圖片
*/
public Bitmap getBitmapFromLocal(String url) {
try {
String fileName = MD5Encoder.encode(url);
File file = new File(CACHE_PATH, fileName);
if (file.exists()) {
Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(
file));
return bitmap;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 向sdcard寫圖片
*
* @param url
* @param bitmap
*/
public void setBitmapToLocal(String url, Bitmap bitmap) {
try {
String fileName = MD5Encoder.encode(url);
File file = new File(CACHE_PATH, fileName);
File parentFile = file.getParentFile();
if (!parentFile.exists()) {// 如果文件夾不存在, 創(chuàng)建文件夾
parentFile.mkdirs();
}
// 將圖片保存在本地
bitmap.compress(CompressFormat.JPEG, 100,
new FileOutputStream(file));
} catch (Exception e) {
e.printStackTrace();
}
}
}
內(nèi)存緩存
兩個方法:設(shè)置內(nèi)存緩存,獲取內(nèi)存緩存
問題:
如果使用HashMap存儲圖片時,當(dāng)圖片越來越多時,會導(dǎo)致內(nèi)存溢出,因?yàn)樗菑?qiáng)引用,java的垃圾回收器不會回收。
如若改成軟引用SoftReference(內(nèi)存不夠時,垃圾回收器會考慮回收),仍有一個問題:在android2.3+, 系統(tǒng)會優(yōu)先將SoftReference的對象提前回收掉, 即使內(nèi)存夠用。
解決辦法:可以用LruCache來解決上述內(nèi)存不回收或提前回收的問題。least recentlly use 最少最近使用算法 它會將內(nèi)存控制在一定的大小內(nèi), 超出最大值時會自動回收, 這個最大值開發(fā)者自己定
public class MemoryCacheUtils {
// private HashMap<String, SoftReference<Bitmap>> mMemoryCache = new
// HashMap<String, SoftReference<Bitmap>>();
private LruCache<String, Bitmap> mMemoryCache;
public MemoryCacheUtils() {
long maxMemory = Runtime.getRuntime().maxMemory() / 8;// 模擬器默認(rèn)是16M
mMemoryCache = new LruCache<String, Bitmap>((int) maxMemory) {
@Override
protected int sizeOf(String key, Bitmap value) {
int byteCount = value.getRowBytes() * value.getHeight();// 獲取圖片占用內(nèi)存大小
return byteCount;
}
};
}
/**
* 從內(nèi)存讀
*
* @param url
*/
public Bitmap getBitmapFromMemory(String url) {
// SoftReference<Bitmap> softReference = mMemoryCache.get(url);
// if (softReference != null) {
// Bitmap bitmap = softReference.get();
// return bitmap;
// }
return mMemoryCache.get(url);
}
/**
* 寫內(nèi)存
*
* @param url
* @param bitmap
*/
public void setBitmapToMemory(String url, Bitmap bitmap) {
// SoftReference<Bitmap> softReference = new
// SoftReference<Bitmap>(bitmap);
// mMemoryCache.put(url, softReference);
mMemoryCache.put(url, bitmap);
}
}
圖片壓縮
//圖片壓縮處理(在從網(wǎng)絡(luò)獲取圖片的時候就進(jìn)行壓縮) BitmapFactory.Options option = new BitmapFactory.Options(); option.inSampleSize = 2;//寬高都壓縮為原來的二分之一, 此參數(shù)需要根據(jù)圖片要展示的大小來確定 option.inPreferredConfig = Bitmap.Config.RGB_565;//設(shè)置圖片格式 Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, option);
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android通過bin二進(jìn)制程序調(diào)用jar原理
最近在研究monkey測試,發(fā)現(xiàn)monkey測試的代碼都是JAVA編寫的,通過編譯生成jar包,而我們在執(zhí)行測試時直接執(zhí)行/system/bin/monkey這個二進(jìn)制程序的,那么它是如何能調(diào)起java程序的呢,本文小編給大家介紹了Android通過bin二進(jìn)制程序調(diào)用jar原理,需要的朋友可以參考下2023-10-10
Android通過AIDL在兩個APP之間Service通信
這篇文章主要為大家詳細(xì)介紹了Android通過AIDL在兩個APP之間Service通信,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-05-05
Android中實(shí)現(xiàn)下載和解壓zip文件功能代碼分享
這篇文章主要介紹了Android中實(shí)現(xiàn)下載和解壓zip文件功能代碼分享,本文直接給出了實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-03-03
Android Handler內(nèi)存泄漏詳解及其解決方案
在android開發(fā)過程中,我們可能會遇到過令人奔潰的OOM異常,這篇文章主要介紹了Android Handler內(nèi)存泄漏詳解及其解決方案,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-08-08
Android開發(fā)之多媒體文件獲取工具類實(shí)例【音頻,視頻,圖片等】
這篇文章主要介紹了Android開發(fā)之多媒體文件獲取工具類,結(jié)合實(shí)例形式分析了Android獲取音頻,視頻及圖片等多媒體資源的相關(guān)操作技巧,需要的朋友可以參考下2017-10-10
Android Gridview布局出現(xiàn)滾動條或組件沖突解決方法
這篇文章主要介紹了Android Gridview布局出現(xiàn)滾動條或組件沖突解決方法,GridView是一個在二維可滾動的網(wǎng)格中展示內(nèi)容的控件。網(wǎng)格中的內(nèi)容通過使用adapter自動插入到布局中2022-07-07

