詳解Android 圖片的三級緩存及圖片壓縮
為什么需要圖片緩存
Android默認給每個應用只分配16M的內(nèi)存,所以如果加載過多的圖片,為了防止內(nèi)存溢出,應該將圖片緩存起來。圖片的三級緩存分別是:
- 內(nèi)存緩存
- 本地緩存
- 網(wǎng)絡(luò)緩存
其中,內(nèi)存緩存應優(yōu)先加載,它速度最快;本地緩存次優(yōu)先加載,它速度也快;網(wǎng)絡(luò)緩存不應該優(yōu)先加載,它走網(wǎng)絡(luò),速度慢且耗流量。
三級緩存的具體實現(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ù)類型 第二個泛型: 更新進度的泛型, 第三個泛型是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); } /** * 更新進度, 主線程 */ @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存儲圖片時,當圖片越來越多時,會導致內(nèi)存溢出,因為它是強引用,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;// 模擬器默認是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ò)獲取圖片的時候就進行壓縮) 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)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android單一實例全局可調(diào)用網(wǎng)絡(luò)加載彈窗
這篇文章主要為大家詳細介紹了Android單一實例全局可調(diào)用網(wǎng)絡(luò)加載彈窗,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-12-12AndroidStudio升級4.1坑(無法啟動、插件plugin不好用、代碼不高亮)
這篇文章主要介紹了AndroidStudio升級4.1坑(無法啟動、插件plugin不好用、代碼不高亮),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-10-10Android開發(fā)之ListView實現(xiàn)Item局部刷新
對于ListView數(shù)據(jù)的刷新大家都知道,改變Adapter的數(shù)據(jù)源,然后調(diào)用Adapter的notifyDateSetChanged()方法即可。通過本篇文章給大家詳細介紹Android開發(fā)之ListView實現(xiàn)Item局部刷新,感興趣的朋友一起學習吧2015-10-10Android獲取應用程序名稱(ApplicationName)示例
本文以實例方式為大家介紹下獲取應用程序名稱(ApplicationName)的具體實現(xiàn),感興趣的各位可以參考下哈2013-06-06