Android高效記憶體之讓你的圖片省記憶體

来源:http://www.cnblogs.com/popfisher/archive/2017/07/28/7249562.html
-Advertisement-
Play Games

Android高效記憶體之讓你的圖片省記憶體 在做記憶體優化的時候,我們發現除瞭解決記憶體泄露問題,剩下的就只有想辦法減少真實的記憶體占用。而在App中,大部分記憶體可能被我們圖片占用了,所以減少圖片的記憶體占用可以帶來直接的效果。 一、一張圖片到底占用多少記憶體 我們先假設我們有一張圖片是600 * 800像素的 ...


Android高效記憶體之讓你的圖片省記憶體

       在做記憶體優化的時候,我們發現除瞭解決記憶體泄露問題,剩下的就只有想辦法減少真實的記憶體占用。而在App中,大部分記憶體可能被我們圖片占用了,所以減少圖片的記憶體占用可以帶來直接的效果。

一、一張圖片到底占用多少記憶體

  我們先假設我們有一張圖片是600 * 800像素的,圖片磁碟占用空間大小假設是 100KB。

圖片記憶體大小跟磁碟占用空間大小有什麼關係?

  磁碟占用空間的大小不是圖片占用記憶體的大小,磁碟占用空間是在磁碟上存儲圖片需要的一個空間大小,記憶體大小是載入到記憶體中占用的記憶體大小。兩個只是單位是一樣的,本質不是一個概念。

一張圖片到底占用多少記憶體呢?

  圖片占用記憶體的計算公式是:圖片高度 * 圖片寬度 * 一個像素占用的記憶體大小,在Android中一般情況下預設一個像素占用記憶體是4個位元組,所以上面的圖片占用記憶體是:800 * 600 * 4 byte = 1875KB = 1.83M。為什麼是4個位元組呢?一定是4個位元組麽?這兩個問題後面仔細講。

圖片所在目錄對記憶體的影響?

  在Android中,圖片的存放目錄和手機的屏幕密度影響圖片最終載入到記憶體的實際大小,舉個例子:假設我們的圖片放到xhdpi目錄下,那麼我們本文中的圖片占用的記憶體大小如下.

  • 屏幕密度為2的設備:800 * 600 * 4byte = 1.83M
  • 屏幕密度為3的設備:800 * 1.5 * 600 * 1.5 * 4byte = 1.83 * 2.25M = 4.12M
  • 這裡所說的屏幕密度是指android.util.DisplayMetrics類中的density變數,是一個float值,關於屏幕密度的更多內容本文不做介紹。

  

  所以,計算圖片占用記憶體大小的時候,要考慮圖片所在的目錄跟屏幕密度,這兩個因素其實影響的是圖片的高寬,Android會對圖片進行拉升跟壓縮。

二、 讓你的圖片省記憶體

2.1 讓你的圖片最小化

  圖片的記憶體占用計算方式為:圖片高度 * 圖片寬度 * 一個像素占用的記憶體大小,所以圖片的高寬如果都變為原來寬高的2倍,那麼記憶體將變為原來的4倍。所以圖片的使用原則可以總結如下:

  1. 使用儘可能小的圖
  2. 使用.9圖,.9圖本身也要儘可能的小
  3. 自己繪製(覆寫View的onDraw自己畫)或者使用Drawable來繪製

比如要實現一個線性漸變效果可以採用以下drawable實現:

 

2.2 在記憶體中壓縮圖片

  載入大圖片時需要對圖片進行壓縮,使用等比例壓縮方法直接在記憶體中處理圖片。

Options options = new BitmapFactory.Options();
options.inSampleSize = 5; // 原圖的五分之一,設置為2則為二分之一
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
                       R.id.myimage, options);

  這樣做要註意的是,圖片質量會變差,inSampleSize設置的值越大,圖片質量就越差。

2.3 讀取點陣圖尺寸和類型時不把圖片載入到記憶體中

  有時候我們取得一張圖片,也許只是為了獲得這個圖片的一些信息,比如圖片的width、height等信息,不需要顯示到界面上,這個時候我們可以不把圖片載入到記憶體中。

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;

2.4 用完就回收

  由於Android外層是使用java,而底層使用的是C語言為圖片對象分配的記憶體空間。所以我們的外部雖然看起來釋放了,但裡層卻並不一定完全釋放了,我們使用完圖片後最好再釋放掉裡層的記憶體空間。

if (!bitmapObject.isRecyled()) {    // Bitmap對象沒有被回收
    bitmapObject.recycle();         // 釋放
    System.gc();                    // 提醒系統及時回收
}

2.5 降低要顯示的圖片色彩質量

2.5.1 顏色模型

RGB(ARGB)

  RGB色彩模式是工業界的一種顏色標準,是通過對紅(R)、綠(G)、藍(B)三個顏色通道的變化以及它們相互之間的疊加來得到各式各樣的顏色的,RGB即是代表紅、綠、藍三個通道的顏色,這個標準幾乎包括了人類視力所能感知的所有顏色,是目前運用最廣的顏色系統之一。在Android中還有包含透明度Alpha的顏色模型,即ARGB。

 

2.5.2 RGB在電腦中顏色值的數字化編碼

  在不考慮透明度的情況下,一個像素點的顏色值在電腦中的表示方法有以下3種:

  1. 浮點數編碼:比如float: (1.0, 0.5, 0.75),每個顏色分量各占1個float欄位,其中1.0表示該分量的值為全紅或全綠或全藍。
  2. 24位的整數編碼:比如24-bit:(255, 128, 196),每個顏色分量各占8位,取值範圍0-255,其中255表示該分量的值為全紅或全綠或全藍。
  3. 16位的整數編碼:比如16-bit:(31, 45, 31),第1和第3個顏色分量各占5位,取值範圍0-31,第2個顏色分量占6位,取值範圍0-63。

  在Java中,float類型的變數占32位,int類型的變數占32位,short和char類型的變數都在16位,因此可以看出,用浮點數表示法編碼一個像素的顏色,記憶體占用量是96位即12位元組;而用24位整數表示法編碼,只要一個int類型變數,占用4個位元組(高8位空著,低24位用於表示顏色);用16位整數表示法編碼,只要一個short類型變數,占2個位元組;因此可以看出採用整數表示法編碼顏色值,可以大大節省記憶體,當然,顏色質量也會相對低一些。在Android中獲取Bitmap的時候一般也採用整型編碼。

2.5.3 Android中RGB編碼格式(整型編碼)

  • RGB888(int):R、G、B分量各占8位
  • RGB565(short):R、G、B分量分別占5、6、5位
  • RGB555(short):RGB分量都用5位表示(剩下的1位不用)
  • ARGB8888(int):A、R、G、B分量各占8位
  • ARGB4444(short):A、R、G、B分量各占4位

  在Android的Bitmap.Config類中,有ARGB_8888、ARGB_4444、RGB565等常量,現在可以知道它們分別代表了什麼含義。

 

  在Android中系統預設使用的編碼格式是ARGB_8888,所以在文章開頭計算圖片記憶體大小的時候每個像素占用記憶體大小是4byte,比如採用ARGB_8888編碼載入一張1920*1200的圖片,大概就會占用1920*1200*4/1024/1024=8.79MB的記憶體。

2.5.4 降低要顯示的圖片色彩質量

  採用低記憶體占用量的編碼方式,比如Bitmap.Config.ARGB_4444比Bitmap.Config.ARGB_8888更省記憶體,比如1920*1200的圖片。

  • ARGB_8888:1920*1200*4/1024/1024=8.79MB
  • ARGB_4444,RGB565:1920*1200*2/1024/1024=4.39MB

三、總結

  在Android中,對圖片的使用一定要關註,大多數情況下,占用記憶體多,OOM發生都是因為圖片資源使用不當。不要盲目加一個大圖到Android項目中,能使用.9進來使用,而且.9圖本身儘可能小,另外能使用繪製實現就不要加一個圖片資源。有些時候,在不影響用戶體驗的情況下,可以降低圖片色彩質量,比如不需要透明度的就不要了,有些透明度用肉眼看不出來。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Struts2(MVC框架)以WebWork為核心,採用攔截器(filter)的機制來處理用戶的請求 官網下載壓縮包解壓: apps文件:Struts2的示例應用 docs文件:struts2的相關文檔 lib文件:struts2的核心庫以及第三方插件類庫 src文件:struts2框架的全包源代碼 ...
  • 最近在看C++ primer plus,感覺函數與指針這一章難點比較多,記寫筆記,加強理解. From C++ Primer Plus: Chapter 7 Function:C++ Programming Modules 1. 如何聲明函數指針? 和函數原型類似: 需要聲明指針指向函數的返回值和參 ...
  • 本文的測試環境:python 2.7 註:新手學習筆記 當前環境下,直接輸入中文,顯然會報錯 Non-ASCII character '\xe4' in file F:/pythons_environment_files/filecheck.py on line 3 這時候你需要在開頭加上 # _* ...
  • 在調用方法時,程式的執行流程會進入方法的內部,當執行到方法內部的return語句或執行完方法內部的代碼以後,則返回到調用該方法的位置繼續向下執行。 方法調用的語法分為以下兩種: (1)一個類內部的方法調用:指調用以及被調用的方法都在一個類的內部。 (2)不同類之間的方法調用:指調用以及被調用的方法位 ...
  • 枚舉類雖然很簡單,但是卻往往是系統中業務邏輯最集中最複雜的地方。本文將會分享我們項目中基於hibernate的枚舉類使用規範,包含資料庫中枚舉列數據類型、註釋、枚舉列與枚舉類的映射等。 一、枚舉類定義規範 請註意,枚舉類一定要包含一個常量字元串用於說明每一個枚舉值的作用。為什麼一定要放在枚舉類裡面? ...
  • intent 一、介紹 二、通過intent連接button和activity實例 三、四種顯示intent 四種顯示intent ...
  • text-overflow: -o-ellipsis-lastline;overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-line-clamp: 2;-webkit-box-orient: vertical; ...
  • activity ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...