A. android的Bitmap操作
src是你的原圖"你好"
下面就衫告是得到褲塌攜原圖的一半胡伏寬度
Bitmap newBitmap = Bitmap.createBitmap(src, 0, 0, src.getWidth()/2, src.getHeight());
B. Android Bitmap理解
參考:
Android Bitmap 詳解:關於 Bitamp 你所要知道的一切
Android Bitmap(點陣圖)詳解
圖片是由大量且有限個數的像素點組成。把一張圖片通過bitmap的方式創建到內存中,實際上就是在內存中創建了一個叫做Bitmap的對象,然後把 圖片所有像素 解碼後的數據存放在Bitmap對象裡面,Bitmap就擁有了圖片的寬高,透明度,顏色值等數據。所以Bitmap的創建是通過BitmapFactory.decodeXxx()。
Config是Bitmap類中的枚舉類。像素由ARGB四個顏色通道組成。Config描述點陣圖中像素的存儲方式。 這里的存儲方式,無非就是對顏色通道和用多大的容器(bit)來存儲的排列組合。所以config會影響圖片透明度,佔用內存大小,保存成文件的大小,圖片質量。
Config的字母表示該配置存儲的像素的顏色通道,數字表示對應通道的數據用多少位來存儲。
ALPHA_8:表示只存儲alpha通道,使用8bit(1位元組)的內存(容器)來存儲一個像素。
RGB_565:表示存儲RGB三個通道,分別使用5bit,6bit,5bit的內存(容器)來存儲一個像素。
ARGB_4444:表示存儲ARGB四個通道,每個通道都是以4bit的內存(容器)來存儲一個像素。
ARGB_8888:表示存儲ARGB四個通道,每個通道都是以8bit的內存(容器)來存儲一個像素。
所以,ARGB_8888配置佔用內存最大,圖片質量最高。
圖片壓縮的一個思路就是降低圖片的配置。
總內存 = 寬的像素數 × 高的像素數 × 每個像素點佔用的大小
註:
1 byte = 8 bit
1 KB = 1024 byte
C. Android-Bitmap復用時內存大小計算
主要是Bitmap的這兩個方法得到的Bitmap的值,會在內存復用體現。
如果不使用內存復用,這兩個方法是一樣的效果。
在通過復用 Bitmap 來解碼圖片時,那麼 getByteCount() 表示新解碼圖片佔用內存的大 小,getAllocationByteCount() 表示被復用 Bitmap真實佔用的內存大小。
比如:上面的圖片,黑色區域是當前Bitmap對象實際內存佔用大小,但是這部分內存中,只有紅色區域是新佔用的,而其他的區域是可以復用的但是沒被復用(即Bitmap中新的圖片只是佔用了8個大小,但是Bitmap實際大小其實是有20),那麼如果使用getByteCount()就只會返回被復用區域的內存大小,所以使用getByteCount()返回內存區域的大小,其實是小於等於實際大小的。
以為你Bitmap佔用內存大小,是由最大的圖片來決定的,如果放入一張更小的圖片,其實並不會減少Bitmap佔用的內存大小。
可以認為:
getByteCount()只是圖片的大小
getAllocationByteCount()是Bitmap的大小
因為Bitmap可以復用,所以Bitmap可以放入不同的圖片,當Bitmap放入更大的圖片的時候,就會佔用更大的內存,但是這個時候如果對Bitmap對象進行復用,放入一張小圖片,並不會改變Bitmap的大小。
D. Android Bitmap 與 Drawable之間的區別和轉換
Android bitmap和drawable的區別和轉換如下:
1.bitmap 轉換 drawable
java">Bitmapbitmap=newBitmap(...);Drawabledrawable=newBitmapDrawable(bitmap);
//Drawabledrawable=newFastBitmapDrawable(bitmap);
2.Drawable to Bitmap
BitmapDrawable, FastBitmapDrawable直接用getBitmap
b. 其他類型的Drawable用Canvas畫到一個bitmap上
Canvascanvas=newCanvas(bitmap)
drawable.draw(canvas);
Drawabled=ImagesList.get(0);Bitmapbitmap=((BitmapDrawable)d).getBitmap();
區別如下:
1.Bitmap - 稱作點陣圖,一般點陣圖的文件格式後綴為bmp,當然編碼器也有很多如RGB565、RGB888。作為一種逐像素的顯示對象執行效率高,但是缺點也很明顯存儲效率低。
2.Drawable - 作為Android平下通用的圖形對象,它可以裝載常用格式的圖像,比如GIF、PNG、JPG,當然也支持BMP,當然還提供一些高級的可視化對象,比如漸變、圖形等。
另外還有如下相類似的格式:
Canvas - 名為畫布,可以看作是一種處理過程,使用各種方法來管理Bitmap、GL或者Path路徑,同時它可以配合Matrix矩陣類給圖像做旋轉、縮放等操作,同時Canvas類還提供了裁剪、選取等操作。
Paint - 可以把它看做一個畫圖工具,比如畫筆、畫刷。管理了每個畫圖工具的字體、顏色、樣式。
E. Android-Bitmap的getByteCount()和getAllocationByteCount()的區別
如果不使用內存復用,這兩個方法是一樣的效果。
在通過復用 Bitmap 來解碼圖片時,那麼 getByteCount() 表示新解碼圖片佔用內存的大 小,getAllocationByteCount() 表示被復用 Bitmap真實佔用的內存大小。
getByteCount()只是圖片的大小
getAllocationByteCount()是Bitmap的大小亮仔
因為Bitmap可爛飢以復用,所以Bitmap可以放入不同的飢鍵返圖片,當Bitmap放入更大的圖片的時候,就會佔用更大的內存,但是這個時候如果對Bitmap對象進行復用,放入一張小圖片,並不會改變Bitmap的大小。
比如,最初Bitmap放入一張大小為4M的圖片,這個時候Bitmap佔用了4M的內存,然後當這張圖片使用完成之後,對Bitmap進行復用,放入一張1M的圖片,這個時候其實只是復用了Bitmap之前內存大小的四分之一,如果使用getByteCount(),得到的其實就是1M,但是這個時候Bitmap對象實際佔用內存其實還是4M,雖然對Bitmap進行了復用,但是並不會因為放入的圖片變小了而改變了原本Bitmap對象佔用內存的大小,所以getAllocationByteCount()返回的是4M
F. Android Bitmap 內存以及OOM問題討論
都知道在Android中, 每個應用所使用的內存是有限的,現在的手機通常最大的內存使用為256M, 目前還沒發現Android中一個應用的最大內存分配超過256M的(經測試華為手機的最大內存是385M)
相關API:
ActivityManager.getMemoryClass(),首先獲取系統服務中的ActivityManager
如下:
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
可以獲取到相關信息
最近一直被項目的OOM問題困擾, 在網上查閱相關資料,前前後後讀了不下於30篇,這些篇幅講解的東西都是千篇一律,並沒有解決到實際問題
也在慕課網學習了內存優化章節
這是慕課網講師的PPT,我截屏的
這里來仔細分析一下:
第一個, 注意臨時Bitmap對象的及時回收, 來看下相關API
直接上圖
經過我無數次的使用Android studio工具自帶的MAT分析工具後, 得出一個很嚴謹的結論, 此方法並不奏效...
Android中Bitmap的內存存放在堆區, Google 的Bitmap的recycle方法注釋也可以了解到
Android歷史版本不是很清楚, 據說Android3.0之前Bitmap是存放在native區域,可以進行手動釋放,然而3.0之後Bitmap是存放在Java層的堆區,沒錯是heap, 內存管理直接交由系統GC管理,你還這樣釋放資源有意義?無非是給自己的一點心理安慰罷了, 告訴你沒卵用
又有人在說要釋放內存使用System.gc() ??? 對就是主動觸發垃圾回收,這個API是開發者自行調用的嗎?那麼系統管理內存還有什麼意義?這不是誤人子弟嗎,這個API不能調用的, 因為沒卵用的, 具體自己參照MAT工具自行分析.即便垃圾回收真的被觸發了, 所有線程停滯由系統來清理垃圾, 造成的後果是嚴重卡頓!!!
再看一個API:
我在網上苦苦追尋內存過高的問題後,發現了這個API,經過無數次實踐後我得出一個結論,沒卵用...開發者可以拋棄它
綜上所訴, 第一點講解的內存優化問題可以直接PASS掉, 無非給自己一點心理安慰: 我已經處理好了內存問題, 程序不會OOM?
第二點. 避免Bitmap的浪費
直接說結論, 這個是非常行之有效的,並且是一定能解決問題的
具體怎麼操作呢? 自己實現LruCache這個類, 就是這么弄, 原理就是解碼復用, 在內存中已經解碼好的Bitmap直接拿出來使用, 沒有的在載入到內存進行解析, 這個非常有效,但是並不能讓你避免OOM
第三點, try-catch某些大內存分配的操作
這點上,我又要開始疑問了, 我Java功底不是很好
Java中發生內存溢出時,拋出的是OutOfMemoryError, 它的父類是VirtualMachineError
這玩意能catch住? 它屬於Error范疇, 你能捕獲?請Java大神出來說一下,我解釋不清楚
第四點, 載入Bitmap 縮放比例, 解碼格式, 局部載入
先來分析一下縮放比例:
按照市面上主流的手機解析度來分析現在Android主流的解析度是1920X1080, 如果一個ImageView控制項剛好就是屏幕全屏,怎麼說?直接佔用掉8M內存, 想想一個實際的需求情況
一個查看大圖的頁面, 不斷的關閉,打開查看新的大圖,問題就來了,內存一直在暴增,遲早會突破界限OOM掉
解析度是2K屏呢? 更恐怖了, 隨著手機設備的屏幕解析度提升, 載入圖像需要的內存也是倍增的, 因為應用的最大內存並沒有增加
結論: 縮放比例可以有效的降低內存佔用問題, 但不是絕對的救命稻草, 該縮放的還是要縮放,而且必須縮放,就是采樣 現在通常都是圖片載入框架來完成,類似Glide.Picasso,Fresco等,他們可以幫助你減少工作量, 內存問題還是存在
再來分析一下解碼格式:
這個跟縮放比例效果差不多, 只是同樣的解析度的圖片載入到內存中時佔用內存減少了
比如ARGB_8888 共32位
RGB_565 共16位
ARGB_4444 共16位
很明顯這樣格式圖片載入的內存情況是ARGB_8888是其他格式的兩倍內存
另外的問題是ARGB_8888看起來很清晰的, 其它的看起來圖片有種糊了的感覺,自己選擇吧
結論, 降低內存佔用非常有效
最後一個是局部載入, 並沒有怎麼使用到,也不清楚就不說了
最後還有一個方法避免OOM, 開啟largeHeap屬性, 但是但是, 以前我們開啟這個屬性後被Oppo應用市場認定為佔用內存過高, 不建議用戶安裝......所以我們又取消了!
總的來說, Bitmap在內存是變現的是不可控, 我項目OOM問題一直沒有得到有效解決,因為圖片編輯視頻編輯之類的功能佔用內存過高,繼續使用OOM是必然的, 跟IOS的同學交流了一番,他們說IOS的應用內存可以佔用到1個G以上, 輕松跑到500M是沒問題的, IOS的內存機制可以持續給內存使用, 具體我也不清楚,並且他們可以手動釋放內存?malloc, free這樣子?
如果大家有比較好的方案,還望留言交流互相幫助 [笑臉.gif]
補充: Android8.0開始Bitmap數據內存存在native層, 單個應用可用的內存顯著增長, 極大的降低了OOM的概率(2018年3月22日)
G. Android:窗口、自定義view、bitmap
1、ViewRoot 對應於 ViewRootImpl 類,它是連接 WindowManager 和 DecorView 的紐帶,View 的三大流程均是通過 ViewRoot 來完成的。在 ActivityThread 中,當 Activity 對象被創建完畢後,會將 DecorView 添加到 Window 中,同時會創建 ViewRootImpl 對象,並將 ViewRootImpl 對棚彎象和 DecorView 建立關聯
2、 自定義View-繪制流程概述
4、 Android Handler
6、 Android Bitmap
2、MeasureSpec:
3、一般來說,使用多進程會造成以下幾個方面的問題:
5、Window 概念與分類:
Window 是一個抽象類,它的具體實現是 PhoneWindow。WindowManager 是外界訪問 Window 的入口,Window 的具體實現位於 WindowManagerService 中,WindowManager 和 WindowManagerService 的交互是一個 IPC 過程。Android 中所有的視圖都是通過 Window 來呈現,因此 Window 實際是 View 的直接管理者。
6、window的三大操作:addView、upView、removeView
7、 Bitmap 中有兩個內部枚舉類:
保存圖片資源:
圖片壓縮:
基本使用:
8、Context 本身是一個抽象類,是對一系列系統服務介面的封裝,包括:內部伏叢資源、包、類載入、I/O操作、許可權、主線程、IPC 和組件啟動等操作的管理。ContextImpl, Activity, Service, Application 這些都是 Context 的直接或間接子類
9、SharedPreferences 採用key-value(鍵值對)形式, 主要用於輕量級的數據存儲, 尤其適合保存應用的配置參數, 但不建議使用 SharedPreferences 來存儲大規模的數據, 可能會降低性能
10、SharedPreferences源碼有用synchronize進行加鎖同步
11、Handler 有兩個主要用途:
(1)安排 Message 和 runnables 在將來的某個時刻執行;
(2)將要在不同鏈廳悶於自己的線程上執行的操作排入隊列。(在多個線程並發更新UI的同時保證線程安全。)
只有主線程能對UI進行操作,所以在對UI進行跟改之前,ViewRootImpl 對UI操作做了驗證,這個驗證工作是由 ViewRootImpl的 checkThread 方法完成:
12、ThreadLocal 是一個線程內部的數據存儲類,通過它可以在指定的線程中存儲數據,其他線程則無法獲取。Looper、ActivityThread 以及 AMS 中都用到了 ThreadLocal。當不同線程訪問同一個ThreadLocal 的 get方法,ThreadLocal 內部會從各自的線程中取出一個數組,然後再從數組中根據當前 ThreadLcoal 的索引去查找對應的value值:
13、Android 提供了幾種途徑來從其他線程訪問 UI 線程:
Android單線程模式必須遵守的規則:
14、HandlerThread 集成了 Thread,卻和普通的 Thread 有顯著的不同。普通的 Thread 主要用於在 run 方法中執行一個耗時任務,而 HandlerThread 在內部創建了消息隊列,外界需要通過 Handler 的消息方式通知 HanderThread 執行一個具體的任務。
15、IntentService 可用於執行後台耗時的任務,當任務執行後會自動停止,由於其是 Service 的原因,它的優先順序比單純的線程要高,所以 IntentService 適合執行一些高優先順序的後台任務。在實現上,IntentService 封裝了 HandlerThread 和 Handler。IntentService 第一次啟動時,會在 onCreatea 方法中創建一個 HandlerThread,然後使用的 Looper 來構造一個 Handler 對象 mServiceHandler,這樣通過 mServiceHandler 發送的消息最終都會在 HandlerThread 中執行。每次啟動 IntentService,它的 onStartCommand 方法就會調用一次,onStartCommand 中處理每個後台任務的 Intent,onStartCommand 調用了 onStart 方法。可以看出,IntentService 僅僅是通過 mServiceHandler 發送了一個消息,這個消息會在 HandlerThread 中被處理。mServiceHandler 收到消息後,會將 Intent 對象傳遞給 onHandlerIntent 方法中處理,執行結束後,通過 stopSelf(int startId) 來嘗試停止服務。(stopSelf() 會立即停止服務,而 stopSelf(int startId) 則會等待所有的消息都處理完畢後才終止服務)。
16、RecyclerView 優化
H. Bitmap使用詳解
用到的圖片不僅僅包括.png、.gif、.9.png、.jpg和各種Drawable系對象,還包括點陣圖Bitmap
圖片的處理也經常是影響著一個程序豎睜的高效性和健壯性。
為什麼不直接用Bitmap傳輸?
點陣圖文件雖好,但是非壓縮格式,佔用較大存儲空間。
Bitmap主要方法有:獲取圖像寬高、釋放,判斷是否已釋放和是否可修改,壓縮、創建制定點陣圖等功能
用於從不同的數據源(如文件、輸入流、資源文件、位元組數組、文件描述符等)解析、創建Bitmap對象
允許我們定義圖片以何種方式戚飢如何讀到內存。
推薦閱讀: Android - Bitmap-內存分析
注意事項:
decodeFileDescriptor比decodeFile高效
查看源碼可以知道
替換成
建議採用decodeStream代替decodeResource。
因為BitmapFactory.decodeResource 載入的圖片可能會經過縮放,該縮放目前是放在 java 層做的,效率比較低,而且需要消耗 java 層的內存。因此,如果大量使用該介面載入圖片,容余仔歲易導致OOM錯誤,BitmapFactory.decodeStream 不會對所載入的圖片進行縮放,相比之下佔用內存少,效率更高。
這兩個介面各有用處,如果對性能要求較高,則應該使用 decodeStream;如果對性能要求不高,且需要 Android 自帶的圖片自適應縮放功能,則可以使用 decodeResource。
推薦閱讀:[ BitmapFactory.decodeResource載入圖片縮小的原因及解決方法
canvas和Matrix可對Bitmap進行旋轉、放縮、平移、切錯等操作
可以用Bitmap.onCreateBitmap、Canvas的clipRect和clipPath等等方式
推薦閱讀: android自定義View學習4--圖像剪切與變換
對初始化Bitmap對象過程中可能發生的OutOfMemory異常進行了捕獲。如果發生了OutOfMemory異常,應用不會崩潰,而是得到了一個默認的Bitmap圖。
如果不進行緩存,盡管看到的是同一張圖片文件,但是使用BitmapFactory類的方法來實例化出來的Bitmap,是不同的Bitmap對象。緩存可以避免新建多個Bitmap對象,避免內存的浪費。
如果圖片像素過大,使用BitmapFactory類的方法實例化Bitmap的過程中,需要大於8M的內存空間,就必定會發生OutOfMemory異常。
可以將圖片縮小,以減少載入圖片過程中的內存的使用,避免異常發生。
推薦閱讀:
Bitmap詳解與Bitmap的內存優化
I. Android Bitmap 與 Drawable之間的區別和轉換
Bitmap - 稱作點陣圖,一般點陣圖的文件格式後綴為bmp,當然編碼器也有很多如RGB565、RGB888。作為一種逐像素的顯示對象蠢念執行效率高,但是缺點也很明顯存儲效率低。我們理解為一種存儲對象比較好。
Drawable - 作為Android平下通用的圖形對象,它可以裝載常用格式的圖像,比如GIF、PNG、JPG,帶銀困當然也支持BMP,當然還提供一些搏歷高級的可視化對象,比如漸變、圖形等。
A bitmap is a Drawable. A Drawable is not necessarily a bitmap. Like all thumbs are fingers but not all fingers are thumbs.
Bitmap是Drawable . Drawable不一定是Bitmap .就像拇指是指頭,但不是所有的指頭都是拇指一樣.
The API dictates: API規定:
Though usually not visible to the application, Drawables may take a variety of forms: 盡管通常情況下對於應用是不可見的,Drawables 可以採取很多形式:
Bitmap: the simplest Drawable, a PNG or JPEG image. Bitmap: 簡單化的Drawable, PNG 或JPEG圖像.
Nine Patch: an extension to the PNG format allows it to specify
information about how to stretch it and place things inside of it.
Shape: contains simple drawing commands instead of a raw bitmap, allowing it to resize better in some cases.
Layers: a compound drawable, which draws multiple underlying drawables on top of each other.
States: a compound drawable that selects one of a set of drawables based on its state.
Levels: a compound drawable that selects one of a set of drawables based on its level.
Scale: a compound drawable with a single child drawable, whose overall size is modified based on the current level.