日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android—Bitmap图片大小计算、压缩与三级缓存

發布時間:2023/12/18 Android 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android—Bitmap图片大小计算、压缩与三级缓存 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Bitmap對象占用內存大小:?bitmap.getByteCount()

圖片所占內存大小計算方式:圖片長度 x 圖片寬度 x 一個像素點占用的字節數。

Android Bitmap使用的三種顏色格式:

  • ALPHA_8–每個像素占1個字節,存儲透明度信息,沒有顏色信息。
  • RGB_565–每個像素占2個字節存儲顏色信息,R 5位,G 6位,B 5位,能表示2^16種顏色。
  • ARGB_8888–每個像素占4個字節存儲顏色信息,A R G B各一個字節,能表示2^24種顏色,還有一個字節存儲透明度信息。

BitmapFactory 類提供了幾種用于從各種來源創建 Bitmap 的解碼方法(decodeStream()、decodeByteArray()、decodeFile()、decodeResource()等)。根據您的圖片數據源選擇最合適的解碼方法。這些方法嘗試為構造的位圖分配內存,因此很容易導致 OutOfMemory 異常。每種類型的解碼方法都有額外的簽名,允許您通過 BitmapFactory.Options 類指定解碼選項。在解碼時將inJustDecodeBounds 屬性設置為 true 可避免內存分配,為位圖對象返回 null,但?outWidth、outHeight 和 outMimeType會被賦值。此方法可讓您在構造位圖并為其分配內存之前讀取圖片數據的尺寸和類型

BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(getResources(), R.id.image, options); //獲取res資源的圖片 int imageHeight = options.outHeight; int imageWidth = options.outWidth; String imageType = options.outMimeType;

壓縮方式:

?質量壓縮:不改變圖片尺寸的情況下,通過損失顏色精度減少圖片的大小。圖片的長,寬,像素都不變,bitmap所占內存大小是不會變的。

bitmap.compress(Bitmap.CompressFormat format, //圖像的壓縮格式;int quality, //圖像壓縮率,0-100。 0 壓縮100%,100意味著不壓縮;OutputStream stream) ; //寫入壓縮數據的輸出流;
  • CompressFormat.JPEG
  • CompressFormat.PNG,因為 PNG 格式是無損的,它無法再進行質量壓縮,quality這個參數就沒有作用了,會被忽略,所以最后圖片保存成的文件大小不會有變化;
  • CompressFormat.WEBP,這個格式是 google 推出的圖片格式,它會比 JPEG 更加省空間。官方表示能節省 25%-34% 的空間;

采樣率壓縮:?降低圖像尺寸,改變圖片的存儲體積。

圖片尺寸的修改其實就是通過修改像素數,放大的過程稱之為上采樣,縮小的過程稱之為下采樣

BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 2; bm = BitmapFactory.decodeFile(imageFilePath, options);

設置inSampleSize的值(int類型)后,假如設為2,則寬和高都為原來的1/2,寬高都減少了,自然內存也降低了。

設置inPreferredConfig:

BitmapFactory.Options options2 = new BitmapFactory.Options(); options2.inPreferredConfig = Bitmap.Config.RGB_565;

圖片大小直接縮小了一半,長度和寬度沒有變,相比argb_8888減少了一半的內存。

createScaledBitmap:

bm = Bitmap.createScaledBitmap(bit, 150, 150, true);

將圖片壓縮成用戶所期望的長度和寬度,但是這里要說,如果用戶期望的長度和寬度和原圖長度寬度相差太多的話,圖片會很不清晰。

Matrix:

我們在自定義 View 控時隨處件可見 Matrix 的身影,主要用于坐標轉換映射,我們可以通過 Matrix 矩陣來控制視圖的變換。

Matrix matrix = new Matrix(); matrix.setScale(0.5f, 0.5f); bm = Bitmap.createBitmap(bit, 0, 0, bit.getWidth(),bit.getHeight(), matrix, true);

內存緩存:LruCache算法

LruCache的算法核心 = LRU 算法 + LinkedHashMap數據結構?

  • LRU(Least Recently Used)最近最少使用
  • LinkedHashMap 哈希表+雙鏈表 用雙鏈表保證了HashMap的順序。
/** * 使用流程(以加載圖片為例)**/ private LruCache<String, Bitmap> mMemoryCache; // 1. 獲得虛擬機能提供的最大內存// 注:超過該大小會拋出OutOfMemory的異常 final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); // 2. 設置LruCache緩存的大小 = 一般為當前進程可用容量的1/8// 注:單位 = Kb// 設置準則// a. 還剩余多少內存給你的activity或應用使用// b. 屏幕上需要一次性顯示多少張圖片和多少圖片在等待顯示// c. 手機的大小和密度是多少(密度越高的設備需要越大的 緩存)// d. 圖片的尺寸(決定了所占用的內存大小)// e. 圖片的訪問頻率(頻率高的在內存中一直保存)// f. 保存圖片的質量(不同像素的在不同情況下顯示)final int cacheSize = maxMemory / 8; // 3. 重寫sizeOf方法:計算緩存對象的大小(此處的緩存對象 = 圖片)mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { @Override protected int sizeOf(String key, Bitmap bitmap) { return bitmap.getByteCount() / 1024; // 此處返回的是緩存對象的緩存大小(單位 = Kb) ,而不是item的個數// 注:緩存的總容量和每個緩存對象的大小所用單位要一致// 此處除1024是為了讓緩存對象的大小單位 = Kb} }; // 4. 將需緩存的圖片 加入到緩存mMemoryCache.put(key, bitmap); // 5. 當 ImageView 加載圖片時,會先在LruCache中看有沒有緩存該圖片:若有,則直接獲取mMemoryCache.get(key);

硬盤緩存:DiskLruCache

打開緩存

public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize) throws IOException

緩存目錄;當前應用程序的版本號;同一個key可以對應多少個緩存文件,基本都是1;最多可以緩存多少字節的數據;

注:每當版本號改變,緩存路徑下存儲的所有數據都會被清除掉,因為DiskLruCache認為當應用程序有版本更新的時候,所有的數據都應該從網上重新獲取。

獲取editor對象

String key = turnToMD5(url); DiskLruCache.Editor editor = mDiskLruCache.edit(key);

key會成為緩存文件的文件名,并且必須要和URL是一一對應的,而URL可能包含特殊字符,不能用作文件名,所以對URL進行MD5編碼,編碼后的字符串是唯一的,并且只會包含0-F字符,符合文件命名規則 。newOutputStream()方法需要傳一個index參數,這里傳入0就好。

轉為MD5方法:?

public String turnToMD5(String key) {String cacheKey;try {final MessageDigest mDigest = MessageDigest.getInstance("MD5");mDigest.update(key.getBytes());cacheKey = bytesToHexString(mDigest.digest());} catch (NoSuchAlgorithmException e) {cacheKey = String.valueOf(key.hashCode());}return cacheKey; }private String bytesToHexString(byte[] bytes) {StringBuilder sb = new StringBuilder();for (int i = 0; i < bytes.length; i++) {String hex = Integer.toHexString(0xFF & bytes[i]);if (hex.length() == 1) {sb.append('0');}sb.append(hex);}return sb.toString(); }

獲得緩存地址對應的輸出流

OutputStream os = editor.newOutputStream(0); // 下載圖片到緩存的輸出流 downloadUrlToStream(imageUrl, outputStream);

如果已經是已有的bitmap對象,通過前面學到的bitmap.compress方法,第三個參數輸出流就可以指定為os從而輸出到緩存路徑。

從網上下載的圖片:?

private boolean downloadUrlToStream(String urlString, OutputStream outputStream) {HttpURLConnection urlConnection = null;BufferedOutputStream out = null;BufferedInputStream in = null;try {final URL url = new URL(urlString);urlConnection = (HttpURLConnection) url.openConnection();in = new BufferedInputStream(urlConnection.getInputStream(), 8 * 1024);out = new BufferedOutputStream(outputStream, 8 * 1024);int b;while ((b = in.read()) != -1) {out.write(b);}return true;} catch (final IOException e) {e.printStackTrace();} finally {if (urlConnection != null) {urlConnection.disconnect();}try {if (out != null) {out.close();}if (in != null) {in.close();}} catch (final IOException e) {e.printStackTrace();}}return false; }

寫完緩存后,調用commit(),來提交緩存;調用abort(),放棄寫入的緩存。

editor.commit();editor.abort();

讀取緩存:

借助DiskLruCache的get()方法實現的

public synchronized Snapshot get(String key) throws IOException

get()方法返回DiskLruCache.Snapshot對象,只需要調用它的getInputStream()方法就可以得到緩存文件的輸入流了。

try {String imageUrl = "https://..............";String key = hashKeyForDisk(imageUrl);DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key);if (snapShot != null) {InputStream is = snapShot.getInputStream(0);Bitmap bitmap = BitmapFactory.decodeStream(is);mImage.setImageBitmap(bitmap);} } catch (IOException e) {e.printStackTrace(); }

DiskLruCache對象其他方法:

  • delete()? 這個方法用于將所有的緩存數據全部刪除
  • close()? ?這個方法用于將DiskLruCache關閉掉,是和open()方法對應的一個方法。
  • flush()? ? 這個方法用于將內存中的操作記錄同步到日志文件(也就是journal文件)當中。
  • size()? ? ?這個方法會返回當前緩存路徑下所有緩存數據的總字節數,以byte為單位,如果應用程序中需要在界面上顯示當前緩存數據的總大小,就可以通過調用這個方法計算出來。

?

?

?

?

?

總結

以上是生活随笔為你收集整理的Android—Bitmap图片大小计算、压缩与三级缓存的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。