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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

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

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

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

圖片所占內(nèi)存大小計(jì)算方式:圖片長度 x 圖片寬度 x 一個(gè)像素點(diǎn)占用的字節(jié)數(shù)。

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

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

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

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;

壓縮方式:

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

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

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

圖片尺寸的修改其實(shí)就是通過修改像素?cái)?shù),放大的過程稱之為上采樣,縮小的過程稱之為下采樣

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

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

設(shè)置inPreferredConfig:

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

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

createScaledBitmap:

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

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

Matrix:

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

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

內(nèi)存緩存:LruCache算法

LruCache的算法核心 = LRU 算法 + LinkedHashMap數(shù)據(jù)結(jié)構(gòu)?

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

硬盤緩存:DiskLruCache

打開緩存

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

緩存目錄;當(dāng)前應(yīng)用程序的版本號;同一個(gè)key可以對應(yīng)多少個(gè)緩存文件,基本都是1;最多可以緩存多少字節(jié)的數(shù)據(jù);

注:每當(dāng)版本號改變,緩存路徑下存儲(chǔ)的所有數(shù)據(jù)都會(huì)被清除掉,因?yàn)镈iskLruCache認(rèn)為當(dāng)應(yīng)用程序有版本更新的時(shí)候,所有的數(shù)據(jù)都應(yīng)該從網(wǎng)上重新獲取。

獲取editor對象

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

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

轉(zhuǎn)為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(); }

獲得緩存地址對應(yīng)的輸出流

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

如果已經(jīng)是已有的bitmap對象,通過前面學(xué)到的bitmap.compress方法,第三個(gè)參數(shù)輸出流就可以指定為os從而輸出到緩存路徑。

從網(wǎng)上下載的圖片:?

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; }

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

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

讀取緩存:

借助DiskLruCache的get()方法實(shí)現(xiàn)的

public synchronized Snapshot get(String key) throws IOException

get()方法返回DiskLruCache.Snapshot對象,只需要調(diào)用它的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()? 這個(gè)方法用于將所有的緩存數(shù)據(jù)全部刪除
  • close()? ?這個(gè)方法用于將DiskLruCache關(guān)閉掉,是和open()方法對應(yīng)的一個(gè)方法。
  • flush()? ? 這個(gè)方法用于將內(nèi)存中的操作記錄同步到日志文件(也就是journal文件)當(dāng)中。
  • size()? ? ?這個(gè)方法會(huì)返回當(dāng)前緩存路徑下所有緩存數(shù)據(jù)的總字節(jié)數(shù),以byte為單位,如果應(yīng)用程序中需要在界面上顯示當(dāng)前緩存數(shù)據(jù)的總大小,就可以通過調(diào)用這個(gè)方法計(jì)算出來。

?

?

?

?

?

總結(jié)

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。