曹幫琴,徐 昊
(信陽職業(yè)技術(shù)學(xué)院數(shù)學(xué)與計算機科學(xué)學(xué)院,河南信陽464000)
作為一款便攜式終端平臺,Android是以Linux內(nèi)核為基礎(chǔ)的開放源碼操作系統(tǒng)[1],主要應(yīng)用于便攜設(shè)備,目前Android已經(jīng)成為全球最受歡迎的智能手機平臺.Android系統(tǒng)以其開源、開放和優(yōu)異便捷的開發(fā)架構(gòu),吸引了眾多程序開發(fā)者,其運行環(huán)境由核心庫集和Dalvik虛擬機組成[2].核心庫集提供了Java編程語言核心庫的大多數(shù)功能,每一個應(yīng)用程序都在它自己的進程中運行,擁有一個獨立的Dalvik虛擬機實例.在編寫應(yīng)用程序時,可以訪問Android提供的API[3],調(diào)用它的C/C++開發(fā)庫及核心應(yīng)用程序包.
隨著移動互聯(lián)網(wǎng)技術(shù)的進步,大量的Android應(yīng)用都會使用分辨率較高的圖片,這些圖片大多以位圖(Bitmap)的形式出現(xiàn).位圖是由稱作像素的單個點組成,圖像數(shù)據(jù)采用非壓縮格式,加載到內(nèi)存時需要占用較大的存儲空間.當(dāng)Android應(yīng)用加載大量圖片到內(nèi)存時,則會有很大概率導(dǎo)致應(yīng)用內(nèi)存溢出[4].如果工程師對Android的內(nèi)存管理機制不了解,很容易造成系統(tǒng)的OOM(Out Of Memory)錯誤,即內(nèi)存溢出錯誤.因此,優(yōu)化Bitmap的使用方法是開發(fā)Android應(yīng)用程序中比較重要的內(nèi)容.
對于一些大量使用Bitmap的項目,影響性能的瓶頸主要是Android系統(tǒng)內(nèi)存管理機制默認分配給應(yīng)用的堆內(nèi)存不足.對于Android平臺,其托管層使用的Dalvik Java VM,還有很多地方可以進行優(yōu)化處理.堆(HEAP)是VM中占用內(nèi)存最多的部分,通常是動態(tài)分配的.堆的大小不是一成不變的,當(dāng)堆內(nèi)存的實際利用率偏離設(shè)定值的時候,虛擬機會在垃圾回收(GC)的時候調(diào)整堆內(nèi)存的大小,讓實際占用率向設(shè)定值靠攏.在開發(fā)一些大型游戲或耗資源的應(yīng)用中可以考慮手動干涉GC處理,使用dalvik.system.VMRuntime類提供的setTargetHeapUtilization方法可以增強程序堆內(nèi)存的處理效率,可以在應(yīng)用onCreate時通過VMRuntime.getRuntime().setTargetHeapUtilization(0.75),把堆內(nèi)存的利用率設(shè)置為75%,優(yōu)化Dalvik虛擬機的堆內(nèi)存分配.除了優(yōu)化Dalvik虛擬機的堆內(nèi)存分配外,還可以使用Dalvik提供的dalvik.system.VMRuntime類重新定義堆內(nèi)存的大小,把最小堆內(nèi)存設(shè)置成16 MB.此方法的缺點是,重新設(shè)置堆內(nèi)存涉及內(nèi)存拷貝,反復(fù)更改堆內(nèi)存的大小勢必影響程序效率.
2.2.1 以最省內(nèi)存的方式讀取本地資源的圖片
Android應(yīng)用在加載圖片時的顏色模式有4種,分別是①ALPHA_8,每像素占用1 byte內(nèi)存;②ARGB_4444,每像素占用2 byte內(nèi)存;③ARGB_8888,每像素占用4 byte內(nèi)存;④RGB_565,每像素占用2 byte內(nèi)存.
Android默認的顏色模式為ARGB_8888,這個顏色模式色彩最細膩、顯示質(zhì)量最高,但占用的內(nèi)存也最大.通過指定加載圖片時的顏色模式,可以達到節(jié)省內(nèi)存的目的,代碼如下:
以上代碼實現(xiàn)了圖片資源以RGB_565模式讀取.對于大多數(shù)圖片,RGB_565(或ARGB_4444)模式與ARGB_8888模式的顯示效果差別不大.此方法的缺點是,由于采用了顯示質(zhì)量一般的顏色模式加載圖片,所以對于漸變效果的圖片可能會出現(xiàn)顏色條.此外,使用RGB_565(或ARGB_4444)模式時會影響圖片的特效處理.
2.2.2 將圖片轉(zhuǎn)化為縮略圖加載
如果圖片的像素過大,在使用BitmapFactory類方法實例化Bitmap的過程中,需要使用的內(nèi)存空間可能超過Android系統(tǒng)分配的空間,從而導(dǎo)致內(nèi)存溢出.如果遇到這種情況,可以在實例化Bitmap時將圖片縮小,減少圖片載入過程中的內(nèi)存占用,避免異常發(fā)生.
在Android應(yīng)用中,使用BitmapFactory.Options設(shè)置inSampleSize屬性可以對圖片進行二次采樣,屬性值inSampleSize表示縮略圖的寬度和高度為完整圖片的幾分之一,代碼如下:
以上代碼實現(xiàn)了讀取縮略圖的功能,由于inSampleSize的值為2,則縮略圖的寬度和高度都是原始圖片的1/2,圖片的大小為原始大小的1/4.這種做法的弊病是圖片質(zhì)量會變差,inSampleSize的值越大,圖片的質(zhì)量就越差.在實際項目中,正確的做法是先獲取圖片真實的寬度和高度,然后判斷是否需要使用縮略圖.如果不需要,設(shè)置inSampleSize的值為1;如果需要,則動態(tài)計算并設(shè)置inSampleSize的值,對圖片進行縮小.
2.3.1 捕獲程序異常
Android應(yīng)用中實例化Bitmap會占用大量內(nèi)存,為了避免應(yīng)用在分配Bitmap內(nèi)存時出現(xiàn)內(nèi)存溢出異常導(dǎo)致的應(yīng)用異常結(jié)束,需要特別注意實例化Bitmap部分的代碼.通常在實例化Bitmap的代碼中,一定要對內(nèi)存溢出異常進行捕獲,代碼如下:
這段代碼通過在初始化Bitmap對象過程中對可能發(fā)生的內(nèi)存溢出異常進行了捕獲和處理,即使出現(xiàn)內(nèi)存溢出的情況,應(yīng)用也不會崩潰,而是得到一個默認的Bitmap位圖.需要注意的是,很多開發(fā)者會習(xí)慣性地在代碼中直接捕獲Exception,但是對于Out Of Memory Error來說,這樣做的結(jié)果是捕獲不到異常的,因為Out Of Memory Error是一種Error,而不是Exception.
2.3.2 及時回收內(nèi)存
由于Bitmap對象占用的內(nèi)存大,在確認不再使用該圖片對象時,可以通過調(diào)用Bitmap對象的recycle()方法及時回收內(nèi)存,有效降低圖片本地數(shù)據(jù)的峰值,減少內(nèi)存溢出的概率.
recycle()方法的作用是標記圖片對象,方便回收圖片對象的本地數(shù)據(jù),及時釋放占用內(nèi)存,并非真正降低Bitmap使用內(nèi)存.使用了recycle()方法的圖片對象處于“廢棄”狀態(tài),再次調(diào)用時會造成程序錯誤,所以在無法保證該圖片對象絕對不會被再次調(diào)用的情況下,不建議使用該方法.特別要注意的是,已經(jīng)用setImageBitmap()方法分配給控件的圖片對象,可能會被系統(tǒng)類庫調(diào)用,造成程序錯誤.
2.3.3 緩存通用的Bitmap對象
在Android應(yīng)用中,經(jīng)常需要在一個Activity里多次用到同一圖片.例如,在一個Activity中展示一些用戶的頭像列表,如果某用戶沒有設(shè)置頭像,則會顯示一個默認頭像.遇到此類應(yīng)用時,如果不進行緩存,而采用BitmapFactory類的方法實例化每個Bitmap,盡管看到的是同一圖片,得到的卻是不同的Bitmap對象.正確的做法是對同一Bitmap對象(默認頭像)進行緩存,避免重復(fù)新建,以減少內(nèi)存占用.
有限的內(nèi)存容量和對內(nèi)存不斷提升的需求始終是矛盾的,Android應(yīng)用不可避免地會使用圖片資源,在處理大量Bitmap數(shù)據(jù)集時避免內(nèi)存的溢出有著十分重要的意義.本研究給出了相應(yīng)的解決方法,通過使用這些方法,在軟件設(shè)計時充分考慮需求并合理地利用技術(shù)有效地管理Android應(yīng)用的內(nèi)存,避免應(yīng)用運行時內(nèi)存溢出.
[1]余志龍,陳昱勛,鄭名杰,等.Google Android SDK開發(fā)范例大全[M].北京:人民郵電出版社,2010.
[2]姚昱曼,劉衛(wèi)國.Android與J2ME平臺間即時通信的研究與實現(xiàn)[J].計算機系統(tǒng)應(yīng)用,2008(12):118-120,127.
[3]黃偉敏.基于XMPP協(xié)議的Android即時通信系統(tǒng)設(shè)計[J].電子設(shè)計工程,2011(19):57-59.
[4]董鋮.針對Android應(yīng)用中Gallery內(nèi)存溢出的解決方案[D].上海:東華大學(xué),2012.