自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Android開發(fā)優(yōu)化之——對Bitmap的內(nèi)存優(yōu)化

移動開發(fā) Android
在Android應(yīng)用里,最耗費內(nèi)存的就是圖片資源。而且在Android系統(tǒng)中,讀取位圖Bitmap時,分給虛擬機中的圖片的堆棧大小只有8M,如果超出了,就會出現(xiàn)OutOfMemory異常。所以,對于圖片的內(nèi)存優(yōu)化,是Android應(yīng)用開發(fā)中比較重要的內(nèi)容。

在Android應(yīng)用里,最耗費內(nèi)存的就是圖片資源。而且在Android系統(tǒng)中,讀取位圖Bitmap時,分給虛擬機中的圖片的堆棧大小只有8M,如果超出了,就會出現(xiàn)OutOfMemory異常。所以,對于圖片的內(nèi)存優(yōu)化,是Android應(yīng)用開發(fā)中比較重要的內(nèi)容。

1) 要及時回收Bitmap的內(nèi)存

Bitmap類有一個方法recycle(),從方法名可以看出意思是回收。這里就有疑問了,Android系統(tǒng)有自己的垃圾回收機制,可以不定期的回收掉不使用的內(nèi)存空間,當(dāng)然也包括Bitmap的空間。那為什么還需要這個方法呢?

Bitmap類的構(gòu)造方法都是私有的,所以開發(fā)者不能直接new出一個Bitmap對象,只能通過BitmapFactory類的各種靜態(tài)方法來實例化一個Bitmap。仔細查看BitmapFactory的源代碼可以看到,生成Bitmap對象最終都是通過JNI調(diào)用方式實現(xiàn)的。所以,加載Bitmap到內(nèi)存里以后,是包含兩部分內(nèi)存區(qū)域的。簡單的說,一部分是Java部分的,一部分是C部分的。這個Bitmap對象是由Java部分分配的,不用的時候系統(tǒng)就會自動回收了,但是那個對應(yīng)的C可用的內(nèi)存區(qū)域,虛擬機是不能直接回收的,這個只能調(diào)用底層的功能釋放。所以需要調(diào)用recycle()方法來釋放C部分的內(nèi)存。從Bitmap類的源代碼也可以看到,recycle()方法里也的確是調(diào)用了JNI方法了的。

那如果不調(diào)用recycle(),是否就一定存在內(nèi)存泄露呢?也不是的。Android的每個應(yīng)用都運行在獨立的進程里,有著獨立的內(nèi)存,如果整個進程被應(yīng)用本身或者系統(tǒng)殺死了,內(nèi)存也就都被釋放掉了,當(dāng)然也包括C部分的內(nèi)存。

Android對于進程的管理是非常復(fù)雜的。簡單的說,Android系統(tǒng)的進程分為幾個級別,系統(tǒng)會在內(nèi)存不足的情況下殺死一些低優(yōu)先級的進程,以提供給其它進程充足的內(nèi)存空間。在實際項目開發(fā)過程中,有的開發(fā)者會在退出程序的時候使用Process.killProcess(Process.myPid())的方式將自己的進程殺死,但是有的應(yīng)用僅僅會使用調(diào)用Activity.finish()方法的方式關(guān)閉掉所有的Activity。

經(jīng)驗分享:

Android手機的用戶,根據(jù)習(xí)慣不同,可能會有兩種方式退出整個應(yīng)用程序:一種是按Home鍵直接退到桌面;另一種是從應(yīng)用程序的退出按鈕或者按Back鍵退出程序。那么從系統(tǒng)的角度來說,這兩種方式有什么區(qū)別呢?按Home鍵,應(yīng)用程序并沒有被關(guān)閉,而是成為了后臺應(yīng)用程序。按Back鍵,一般來說,應(yīng)用程序關(guān)閉了,但是進程并沒有被殺死,而是成為了空進程(程序本身對退出做了特殊處理的不考慮在內(nèi))。

Android系統(tǒng)已經(jīng)做了大量進程管理的工作,這些已經(jīng)可以滿足用戶的需求。個人建議,應(yīng)用程序在退出應(yīng)用的時候不需要手動殺死自己所在的進程。對于應(yīng)用程序本身的進程管理,交給Android系統(tǒng)來處理就可以了。應(yīng)用程序需要做的,是盡量做好程序本身的內(nèi)存管理工作。

一般來說,如果能夠獲得Bitmap對象的引用,就需要及時的調(diào)用Bitmap的recycle()方法來釋放Bitmap占用的內(nèi)存空間,而不要等Android系統(tǒng)來進行釋放。

下面是釋放Bitmap的示例代碼片段。

  1. // 先判斷是否已經(jīng)回收 
  2.  
  3. if(bitmap != null && !bitmap.isRecycled()){   
  4.  
  5.         // 回收并且置為null 
  6.  
  7.         bitmap.recycle();   
  8.  
  9.         bitmap = null;   
  10.  
  11. }   
  12.  
  13. System.gc(); 
  14.   

從上面的代碼可以看到,bitmap.recycle()方法用于回收該Bitmap所占用的內(nèi)存,接著將bitmap置空,最后使用System.gc()調(diào)用一下系統(tǒng)的垃圾回收器進行回收,可以通知垃圾回收器盡快進行回收。這里需要注意的是,調(diào)用System.gc()并不能保證立即開始進行回收過程,而只是為了加快回收的到來。

如何調(diào)用recycle()方法進行回收已經(jīng)了解了,那什么時候釋放Bitmap的內(nèi)存比較合適呢?一般來說,如果代碼已經(jīng)不再需要使用Bitmap對象了,就可以釋放了。釋放內(nèi)存以后,就不能再使用該Bitmap對象了,如果再次使用,就會拋出異常。所以一定要保證不再使用的時候釋放。比如,如果是在某個Activity中使用Bitmap,就可以在Activity的onStop()或者onDestroy()方法中進行回收。

2) 捕獲異常

因為Bitmap是吃內(nèi)存大戶,為了避免應(yīng)用在分配Bitmap內(nèi)存的時候出現(xiàn)OutOfMemory異常以后Crash掉,需要特別注意實例化Bitmap部分的代碼。通常,在實例化Bitmap的代碼中,一定要對OutOfMemory異常進行捕獲。

以下是代碼示例。

  1. Bitmap bitmap = null
  2.  
  3. try { 
  4.  
  5.     // 實例化Bitmap 
  6.  
  7.     bitmap = BitmapFactory.decodeFile(path); 
  8.  
  9. catch (OutOfMemoryError e) { 
  10.  
  11.     // 
  12.  
  13.  
  14. if (bitmap == null) { 
  15.  
  16.     // 如果實例化失敗 返回默認的Bitmap對象 
  17.  
  18.     return defaultBitmapMap; 
  19.  
  20.   

這里對初始化Bitmap對象過程中可能發(fā)生的OutOfMemory異常進行了捕獲。如果發(fā)生了OutOfMemory異常,應(yīng)用不會崩潰,而是得到了一個默認的Bitmap圖。

經(jīng)驗分享:

    很多開發(fā)者會習(xí)慣性的在代碼中直接捕獲Exception。但是對于OutOfMemoryError來說,這樣做是捕獲不到的。因為OutOfMemoryError是一種Error,而不是Exception。在此僅僅做一下提醒,避免寫錯代碼而捕獲不到OutOfMemoryError。

3) 緩存通用的Bitmap對象

有時候,可能需要在一個Activity里多次用到同一張圖片。比如一個Activity會展示一些用戶的頭像列表,而如果用戶沒有設(shè)置頭像的話,則會顯示一個默認頭像,而這個頭像是位于應(yīng)用程序本身的資源文件中的。

如果有類似上面的場景,就可以對同一Bitmap進行緩存。如果不進行緩存,盡管看到的是同一張圖片文件,但是使用BitmapFactory類的方法來實例化出來的Bitmap,是不同的Bitmap對象。緩存可以避免新建多個Bitmap對象,避免內(nèi)存的浪費。

經(jīng)驗分享:

    Web開發(fā)者對于緩存技術(shù)是很熟悉的。其實在Android應(yīng)用開發(fā)過程中,也會經(jīng)常使用緩存的技術(shù)。這里所說的緩存有兩個級別,一個是硬盤緩存,一個是內(nèi)存緩存。比如說,在開發(fā)網(wǎng)絡(luò)應(yīng)用過程中,可以將一些從網(wǎng)絡(luò)上獲取的數(shù)據(jù)保存到SD卡中,下次直接從SD卡讀取,而不從網(wǎng)絡(luò)中讀取,從而節(jié)省網(wǎng)絡(luò)流量。這種方式就是硬盤緩存。再比如,應(yīng)用程序經(jīng)常會使用同一對象,也可以放到內(nèi)存中緩存起來,需要的時候直接從內(nèi)存中讀取。這種方式就是內(nèi)存緩存。

4) 壓縮圖片

如果圖片像素過大,使用BitmapFactory類的方法實例化Bitmap的過程中,需要大于8M的內(nèi)存空間,就必定會發(fā)生OutOfMemory異常。這個時候該如何處理呢?如果有這種情況,則可以將圖片縮小,以減少載入圖片過程中的內(nèi)存的使用,避免異常發(fā)生。

使用BitmapFactory.Options設(shè)置inSampleSize就可以縮小圖片。屬性值inSampleSize表示縮略圖大小為原始圖片大小的幾分之一。即如果這個值為2,則取出的縮略圖的寬和高都是原始圖片的1/2,圖片的大小就為原始大小的1/4。

如果知道圖片的像素過大,就可以對其進行縮小。那么如何才知道圖片過大呢?

使用BitmapFactory.Options設(shè)置inJustDecodeBounds為true后,再使用decodeFile()等方法,并不會真正的分配空間,即解碼出來的Bitmap為null,但是可計算出原始圖片的寬度和高度,即options.outWidth和options.outHeight。通過這兩個值,就可以知道圖片是否過大了。

  1. BitmapFactory.Options opts = new BitmapFactory.Options(); 
  2.  
  3.     // 設(shè)置inJustDecodeBounds為true 
  4.  
  5.     opts.inJustDecodeBounds = true
  6.  
  7.     // 使用decodeFile方法得到圖片的寬和高 
  8.  
  9.     BitmapFactory.decodeFile(path, opts); 
  10.  
  11.     // 打印出圖片的寬和高 
  12.  
  13.     Log.d("example", opts.outWidth + "," + opts.outHeight); 
  14.   

在實際項目中,可以利用上面的代碼,先獲取圖片真實的寬度和高度,然后判斷是否需要跑縮小。如果不需要縮小,設(shè)置inSampleSize的值為1。如果需要縮小,則動態(tài)計算并設(shè)置inSampleSize的值,對圖片進行縮小。需要注意的是,在下次使用BitmapFactory的decodeFile()等方法實例化Bitmap對象前,別忘記將opts.inJustDecodeBound設(shè)置回false。否則獲取的bitmap對象還是null。

經(jīng)驗分享:

如果程序的圖片的來源都是程序包中的資源,或者是自己服務(wù)器上的圖片,圖片的大小是開發(fā)者可以調(diào)整的,那么一般來說,就只需要注意使用的圖片不要過大,并且注意代碼的質(zhì)量,及時回收Bitmap對象,就能避免OutOfMemory異常的發(fā)生。

如果程序的圖片來自外界,這個時候就特別需要注意OutOfMemory的發(fā)生。一個是如果載入的圖片比較大,就需要先縮??;另一個是一定要捕獲異常,避免程序Crash。

責(zé)任編輯:張葉青 來源: 技術(shù)博客
相關(guān)推薦

2013-09-16 15:42:00

Android優(yōu)化界面UI

2013-09-16 15:50:04

Android優(yōu)化界面UI

2013-09-16 15:33:28

Android優(yōu)化界面UI

2013-02-20 14:32:37

Android開發(fā)性能

2013-09-16 16:01:23

Android開發(fā)代碼

2014-10-30 10:53:22

Android內(nèi)存優(yōu)化

2021-07-29 14:20:34

網(wǎng)絡(luò)優(yōu)化移動互聯(lián)網(wǎng)數(shù)據(jù)存儲

2017-12-23 14:38:41

Android編程開發(fā)優(yōu)化

2019-12-13 10:25:08

Android性能優(yōu)化啟動優(yōu)化

2017-01-15 15:13:37

Android性能優(yōu)化優(yōu)化點

2017-03-14 18:48:06

Android性能優(yōu)化內(nèi)存優(yōu)化

2013-09-17 10:32:08

Android性能優(yōu)化數(shù)據(jù)庫

2013-09-16 13:14:50

Android開發(fā)者優(yōu)化

2017-02-14 17:00:39

iOSApp內(nèi)存優(yōu)化

2015-09-16 15:21:23

Android性能優(yōu)化內(nèi)存

2016-12-22 17:21:11

Android性能優(yōu)化內(nèi)存泄漏

2013-05-21 10:42:48

Android游戲開發(fā)Bitmap位圖旋轉(zhuǎn)

2011-06-22 17:11:18

SEO

2013-09-16 16:48:50

Android優(yōu)化軟引用

2021-08-03 16:35:04

AndroidANR內(nèi)存
點贊
收藏

51CTO技術(shù)棧公眾號