在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Android/ 管理應用的內存
檢測常用的手勢
優(yōu)化layout的層級
用戶輸入
管理應用的內存
聯(lián)系人信息
開發(fā)輔助程序
Android多媒體
添加語音功能
顯示位置地址
提供向下與橫向導航
支持游戲控制器
訪問可穿戴數(shù)據(jù)層
處理多點觸控手勢
全屏沉浸式應用
為多線程創(chuàng)建管理器
數(shù)據(jù)保存
Intent的發(fā)送
更新Notification
優(yōu)化下載以高效地訪問網絡
打印
打包可穿戴應用
接收從其他App傳送來的數(shù)據(jù)
發(fā)送與接收消息
建立靈活動態(tài)的UI
處理鍵盤輸入
Building a Work Policy Controller
建立測試環(huán)境
創(chuàng)建表盤
分享文件
顯示Notification進度
實現(xiàn)自適應UI流(Flows)
使用設備管理策略增強安全性
使用能感知版本的組件
執(zhí)行網絡操作
建立文件分享
添加移動
更新你的Security Provider來對抗SSL漏洞利用
支持鍵盤導航
創(chuàng)建和監(jiān)視地理圍欄
發(fā)送并同步數(shù)據(jù)
使用BigView樣式
無線連接設備
提供向上導航與歷史導航
最小化定期更新造成的影響
實現(xiàn)向下的導航
支持不同的屏幕大小
Android 可穿戴應用
添加動畫
顯示聯(lián)系人頭像
使用OpenGL ES顯示圖像
處理輸入法可見性
分享文件
保持設備喚醒
淡化系統(tǒng)Bar
使用NFC分享文件
保存到Preference
Android聯(lián)系人信息與位置信息
創(chuàng)建標準的網絡請求
使用Drawables
管理Bitmap的內存使用
管理Activity的生命周期
按需加載視圖
傳輸資源
為可穿戴設備創(chuàng)建自定義UI
在一個線程中執(zhí)行一段特定的代碼
性能優(yōu)化
隱藏導航欄
創(chuàng)建目錄瀏覽器
為多種大小的屏幕進行規(guī)劃
View間漸變
使用觸摸手勢
高效加載大圖
使用CursorLoader在后臺加載數(shù)據(jù)
創(chuàng)建抽屜式導航(navigation drawer)
管理音頻焦點
創(chuàng)建后臺服務
創(chuàng)建功能測試
創(chuàng)建使用Material Design的應用
停止與重啟Activity
添加一個簡便的分享功能
啟動Activity時保留導航
TV應用清單
創(chuàng)建向后兼容的UI
?# 優(yōu)化自定義View
創(chuàng)建單元測試
在UI上顯示Bitmap
建立OpenGL ES的環(huán)境
構建表盤服務
JNI Tips
建立搜索界面
實現(xiàn)自定義View的繪制
使用HTTPS與SSL
按需操控BroadcastReceiver
分享簡單的數(shù)據(jù)
繪制形狀
Android位置信息
創(chuàng)建并運行可穿戴應用
執(zhí)行 Sync Adpater
獲取最后可知位置
創(chuàng)建 Android 項目
實現(xiàn)高效的導航
退出全屏的Activity
創(chuàng)建Card
兼容音頻輸出設備
同步數(shù)據(jù)單元
傳輸數(shù)據(jù)時避免消耗大量電量
保存到文件
緩存Bitmap
提供配置 Activity
調度重復的鬧鐘
實現(xiàn)輔助功能
重復的下載是冗余的
隱藏狀態(tài)欄
實現(xiàn)自定義的網絡請求
規(guī)劃界面和他們之間的關系
使用Sync Adapter傳輸數(shù)據(jù)
TV應用內搜索
響應觸摸事件
使用Google Cloud Messaging(已廢棄)
控制相機
Android網絡連接與云服務
請求分享一個文件
處理TV硬件
響應UI可見性的變化
使用網絡服務發(fā)現(xiàn)
指定輸入法類型
優(yōu)化電池壽命
創(chuàng)建TV應用
獲取聯(lián)系人列表
拖拽與縮放
啟動與停止線程池中的線程
創(chuàng)建 Sync Adpater
使用 WiFi P2P 服務發(fā)現(xiàn)
開始使用Material Design
代理至新的APIs
使用include標簽重用layouts
使得View可交互
高效顯示Bitmap
創(chuàng)建企業(yè)級應用
Fragments之間的交互
創(chuàng)建與執(zhí)行測試用例
綜合:設計我們的樣例 App
繪制表盤
建立簡單的用戶界面
自定義動畫
開發(fā)輔助服務
避免出現(xiàn)程序無響應ANR(Keeping Your App Responsive)
使用ViewPager實現(xiàn)屏幕滑動
設計高效的導航
Android分享操作(Building Apps with Content Sharing)
提供向后的導航
保持向下兼容
創(chuàng)建TV播放應用
縮放View
使用 WiFi 建立 P2P 連接
Android后臺任務
連接到網絡
為 Notification 添加頁面
使TV應用是可被搜索的
添加Action Bar
使用Material的主題
啟動另一個Activity
顯示正在播放卡片
適配不同的系統(tǒng)版本
輕松錄制視頻
創(chuàng)建可穿戴的應用
創(chuàng)建自定義的布局
重新創(chuàng)建Activity
使用CursorLoader執(zhí)行查詢任務
使用舊的APIs實現(xiàn)新API的效果
使用備份API
安全要點
Android入門基礎:從這里開始
保存并搜索數(shù)據(jù)
根據(jù)網絡連接類型來調整下載模式
使用Tabs創(chuàng)建Swipe視圖
SMP(Symmetric Multi-Processor) Primer for Android
解析 XML 數(shù)據(jù)
使用 Volley 傳輸網絡數(shù)據(jù)
建立ActionBar
Android交互設計
使用Intent修改聯(lián)系人信息
增加搜索功能
輕松拍攝照片
定義形狀
測試你的Activity
在 Notifcation 中接收語音輸入
與其他應用的交互
管理系統(tǒng)UI
追蹤手勢移動
Android界面設計
執(zhí)行 Android 程序
顯示確認界面
創(chuàng)建Lists與Cards
打印HTML文檔
創(chuàng)建TV應用
為多屏幕設計
定義Shadows與Clipping視圖
使用Fragment建立動態(tài)UI
接收Activity返回的結果
布局變更動畫
定位常見的問題
自定義ActionBar的風格
定義Layouts
發(fā)送簡單的網絡請求
啟動與銷毀Activity
與UI線程通信
非UI線程處理Bitmap
創(chuàng)建TV布局
提升Layout的性能
報告任務執(zhí)行狀態(tài)
判斷并監(jiān)測網絡連接狀態(tài)
兼容不同的設備
處理按鍵動作
優(yōu)化性能和電池使用時間
給其他App發(fā)送簡單的數(shù)據(jù)
Implementing App Restrictions
向后臺服務發(fā)送任務請求
展示Card翻轉動畫
管理ViewGroup中的觸摸事件
兼容不同的屏幕密度
通過藍牙進行調試
為可穿戴設備創(chuàng)建Notification
控制音量與音頻播放
獲取聯(lián)系人詳情
在表盤上顯示信息
提供向上的導航
滾動手勢動畫
幫助用戶在TV上找到內容
創(chuàng)建TV導航
為索引指定App內容
ActionBar的覆蓋疊加
Android Wear 上的位置檢測
保護安全與隱私的最佳策略
Ensuring Compatibility with Managed Profiles
解決云同步的保存沖突
獲取位置更新
創(chuàng)建List
測試程序
管理網絡的使用情況
為App內容開啟深度鏈接
推薦TV內容
建立一個Notification
管理音頻播放
設計表盤
拍照
處理控制器輸入動作
判斷并監(jiān)測設備的底座狀態(tài)與類型
處理查詢的結果
保存到數(shù)據(jù)庫
支持多個游戲控制器
創(chuàng)建 Stub Content Provider
使得ListView滑動順暢
處理數(shù)據(jù)層的事件
創(chuàng)建TV應用的第一步
使得你的App內容可被Google搜索
將 Notification 放成一疊
創(chuàng)建 Stub 授權器
暫停與恢復Activity
管理設備的喚醒狀態(tài)
Android圖像與動畫
打印照片
云同步
創(chuàng)建TV直播應用
為Notification賦加可穿戴特性
提供一個Card視圖
建立請求隊列(RequestQueue)
適配不同的語言
創(chuàng)建詳情頁
測試UI組件
接收其他設備的文件
創(chuàng)建自定義View
建立第一個App
創(chuàng)建2D Picker
監(jiān)測電池的電量與充電狀態(tài)
打印自定義文檔
抽象出新的APIs
通知提示用戶
獲取文件信息
運用投影與相機視角
在IntentService中執(zhí)行后臺任務
多線程操作
創(chuàng)建一個Fragment
添加Action按鈕
在不同的 Android 系統(tǒng)版本支持控制器
維護兼容性
發(fā)送文件給其他設備
創(chuàng)建TV游戲應用
創(chuàng)建自定義的View類
代碼性能優(yōu)化建議
Intent過濾
適配不同的屏幕

管理應用的內存

編寫:kesenhoo - 原文:http://developer.android.com/training/articles/memory.html

Random Access Memory(RAM)在任何軟件開發(fā)環(huán)境中都是一個很寶貴的資源。這一點在物理內存通常很有限的移動操作系統(tǒng)上,顯得尤為突出。盡管Android的Dalvik虛擬機扮演了常規(guī)的垃圾回收的角色,但這并不意味著你可以忽視app的內存分配與釋放的時機與地點。

為了GC能夠從app中及時回收內存,我們需要注意避免內存泄露(通常由于在全局成員變量中持有對象引用而導致)并且在適當?shù)臅r機(下面會講到的lifecycle callbacks)來釋放引用對象。對于大多數(shù)app來說,Dalvik的GC會自動把離開活動線程的對象進行回收。

這篇文章會解釋Android是如何管理app的進程與內存分配,以及在開發(fā)Android應用的時候如何主動的減少內存的使用。關于Java的資源管理機制,請參考其它書籍或者線上材料。如果你正在尋找如何分析你的內存使用情況的文章,請參考這里Investigating Your RAM Usage。

第1部分: Android是如何管理內存的

Android并沒有為內存提供交換區(qū)(Swap space),但是它有使用pagingmemory-mapping(mmapping)的機制來管理內存。這意味著任何你修改的內存(無論是通過分配新的對象還是去訪問mmaped pages中的內容)都會貯存在RAM中,而且不能被paged out。因此唯一完整釋放內存的方法是釋放那些你可能hold住的對象的引用,當這個對象沒有被任何其他對象所引用的時候,它就能夠被GC回收了。只有一種例外是:如果系統(tǒng)想要在其他地方重用這個對象。

1) 共享內存

Android通過下面幾個方式在不同的進程中來實現(xiàn)共享RAM:

  • 每一個app的進程都是從一個被叫做Zygote的進程中fork出來的。Zygote進程在系統(tǒng)啟動并且載入通用的framework的代碼與資源之后開始啟動。為了啟動一個新的程序進程,系統(tǒng)會fork Zygote進程生成一個新的進程,然后在新的進程中加載并運行app的代碼。這使得大多數(shù)的RAM pages被用來分配給framework的代碼,同時使得RAM資源能夠在應用的所有進程中進行共享。

  • 大多數(shù)static的數(shù)據(jù)被mmapped到一個進程中。這不僅僅使得同樣的數(shù)據(jù)能夠在進程間進行共享,而且使得它能夠在需要的時候被paged out。例如下面幾種static的數(shù)據(jù):
    • Dalvik 代碼 (放在一個預鏈接好的 .odex 文件中以便直接mapping)
    • App resources (通過把資源表結構設計成便于mmapping的數(shù)據(jù)結構,另外還可以通過把APK中的文件做aligning的操作來優(yōu)化)
    • 傳統(tǒng)項目元素,比如 .so 文件中的本地代碼.
  • 在很多情況下,Android通過顯式的分配共享內存區(qū)域(例如ashmem或者gralloc)來實現(xiàn)一些動態(tài)RAM區(qū)域能夠在不同進程間進行共享。例如,window surfaces在app與screen compositor之間使用共享的內存,cursor buffers在content provider與client之間使用共享的內存。

關于如何查看app所使用的共享內存,請查看Investigating Your RAM Usage

2) 分配與回收內存

這里有下面幾點關于Android如何分配與回收內存的事實:

  • 每一個進程的Dalvik heap都有一個受限的虛擬內存范圍。這就是邏輯上講的heap size,它可以隨著需要進行增長,但是會有一個系統(tǒng)為它所定義的上限。
  • 邏輯上講的heap size和實際物理上使用的內存數(shù)量是不等的,Android會計算一個叫做Proportional Set Size(PSS)的值,它記錄了那些和其他進程進行共享的內存大小。(假設共享內存大小是10M,一共有20個Process在共享使用,根據(jù)權重,可能認為其中有0.3M才能真正算是你的進程所使用的)
  • Dalvik heap與邏輯上的heap size不吻合,這意味著Android并不會去做heap中的碎片整理用來關閉空閑區(qū)域。Android僅僅會在heap的尾端出現(xiàn)不使用的空間時才會做收縮邏輯heap size大小的動作。但是這并不是意味著被heap所使用的物理內存大小不能被收縮。在垃圾回收之后,Dalvik會遍歷heap并找出不使用的pages,然后使用madvise(系統(tǒng)調用)把那些pages返回給kernal。因此,成對的allocations與deallocations大塊的數(shù)據(jù)可以使得物理內存能夠被正常的回收。然而,回收碎片化的內存則會使得效率低下很多,因為那些碎片化的分配頁面也許會被其他地方所共享到。

3) 限制應用的內存

為了維持多任務的功能環(huán)境,Android為每一個app都設置了一個硬性的heap size限制。準確的heap size限制會因為不同設備的不同RAM大小而各有差異。如果你的app已經到了heap的限制大小并且再嘗試分配內存的話,會引起OutOfMemoryError的錯誤。

在一些情況下,你也許想要查詢當前設備的heap size限制大小是多少,然后決定cache的大小??梢酝ㄟ^getMemoryClass()來查詢。這個方法會返回一個整數(shù),表明你的應用的heap size限制是多少Mb(megabates)。

4) 切換應用

Android并不會在用戶切換不同應用時候做交換內存的操作。Android會把那些不包含foreground組件的進程放到LRU cache中。例如,當用戶剛開始啟動了一個應用,系統(tǒng)會為它創(chuàng)建了一個進程,但是當用戶離開這個應用,此進程并不會立即被銷毀。系統(tǒng)會把這個進程放到cache中,如果用戶后來再回到這個應用,此進程就能夠被完整恢復,從而實現(xiàn)應用的快速切換。

如果你的應用中有一個被緩存的進程,這個進程會占用暫時不需要使用到的內存,這個暫時不需要使用的進程,它被保留在內存中,這會對系統(tǒng)的整體性能有影響。因此當系統(tǒng)開始進入低內存狀態(tài)時,它會由系統(tǒng)根據(jù)LRU的規(guī)則與其他因素選擇綜合考慮之后決定殺掉某些進程,為了保持你的進程能夠盡可能長久的被緩存,請參考下面的章節(jié)學習何時釋放你的引用。

對于那些不在foreground的進程,Android是如何決定kill掉哪一類進程的問題,請參考Processes and Threads.

第2部分: 你的應用該如何管理內存

你應該在開發(fā)過程的每一個階段都考慮到RAM的有限性,甚至包括在開始編寫代碼之前的設計階段就應該考慮到RAM的限制性。我們可以使用多種設計與實現(xiàn)方式,他們有著不同的效率,即使這些方式只是相同技術的不斷組合與演變。

為了使得你的應用性能效率更高,你應該在設計與實現(xiàn)代碼時,遵循下面的技術要點。

1) 珍惜Services資源

如果你的應用需要在后臺使用service,除非它被觸發(fā)并執(zhí)行一個任務,否則其他時候service都應該是停止狀態(tài)。另外需要注意當這個service完成任務之后因為停止service失敗而引起的內存泄漏。

當你啟動一個service,系統(tǒng)會傾向為了保留這個service而一直保留service所在的進程。這使得進程的運行代價很高,因為系統(tǒng)沒有辦法把service所占用的RAM空間騰出來讓給其他組件,另外service還不能被paged out。這減少了系統(tǒng)能夠存放到LRU緩存當中的進程數(shù)量,它會影響app之間的切換效率。它甚至會導致系統(tǒng)內存使用不穩(wěn)定,從而無法繼續(xù)保持住所有目前正在運行的service。

限制你的service的最好辦法是使用IntentService, 它會在處理完交代給它的intent任務之后盡快結束自己。更多信息,請閱讀Running in a Background Service.

當一個Service已經不再需要的時候還繼續(xù)保留它,這對Android應用的內存管理來說是最糟糕的錯誤之一。因此千萬不要貪婪的使得一個Service持續(xù)保留。不僅僅是因為它會使得你的應用因為RAM空間的不足而性能糟糕,還會使得用戶發(fā)現(xiàn)那些有著常駐后臺行為的應用并且可能卸載它。

2) 當UI隱藏時釋放內存

當用戶切換到其它應用并且你的應用 UI不再可見時,你應該釋放你的應用UI上所占用的所有內存資源。在這個時候釋放UI資源可以顯著的增加系統(tǒng)緩存進程的能力,它會對用戶體驗有著很直接的影響。

為了能夠接收到用戶離開你的UI時的通知,你需要實現(xiàn)Activtiy類里面的onTrimMemory()回調方法。你應該使用這個方法來監(jiān)聽到TRIM_MEMORY_UI_HIDDEN級別的回調,此時意味著你的UI已經隱藏,你應該釋放那些僅僅被你的UI使用的資源。

請注意:你的應用僅僅會在所有UI組件的被隱藏的時候接收到onTrimMemory()的回調并帶有參數(shù)TRIM_MEMORY_UI_HIDDEN。這與onStop()的回調是不同的,onStop會在activity的實例隱藏時會執(zhí)行,例如當用戶從你的app的某個activity跳轉到另外一個activity時前面activity的onStop()會被執(zhí)行。因此你應該實現(xiàn)onStop回調,并且在此回調里面釋放activity的資源,例如釋放網絡連接,注銷監(jiān)聽廣播接收者。除非接收到onTrimMemory(TRIM_MEMORY_UI_HIDDEN)的回調,否者你不應該釋放你的UI資源。這確保了用戶從其他activity切回來時,你的UI資源仍然可用,并且可以迅速恢復activity。

3) 當內存緊張時釋放部分內存

在你的app生命周期的任何階段,onTrimMemory的回調方法同樣可以告訴你整個設備的內存資源已經開始緊張。你應該根據(jù)onTrimMemory回調中的內存級別來進一步決定釋放哪些資源。

  • TRIM_MEMORY_RUNNING_MODERATE:你的app正在運行并且不會被列為可殺死的。但是設備此時正運行于低內存狀態(tài)下,系統(tǒng)開始觸發(fā)殺死LRU Cache中的Process的機制。
  • TRIM_MEMORY_RUNNING_LOW:你的app正在運行且沒有被列為可殺死的。但是設備正運行于更低內存的狀態(tài)下,你應該釋放不用的資源用來提升系統(tǒng)性能(但是這也會直接影響到你的app的性能)。
  • TRIM_MEMORY_RUNNING_CRITICAL:你的app仍在運行,但是系統(tǒng)已經把LRU Cache中的大多數(shù)進程都已經殺死,因此你應該立即釋放所有非必須的資源。如果系統(tǒng)不能回收到足夠的RAM數(shù)量,系統(tǒng)將會清除所有的LRU緩存中的進程,并且開始殺死那些之前被認為不應該殺死的進程,例如那個包含了一個運行態(tài)Service的進程。

同樣,當你的app進程正在被cached時,你可能會接受到從onTrimMemory()中返回的下面的值之一:

  • TRIM_MEMORY_BACKGROUND: 系統(tǒng)正運行于低內存狀態(tài)并且你的進程正處于LRU緩存名單中最不容易殺掉的位置。盡管你的app進程并不是處于被殺掉的高危險狀態(tài),系統(tǒng)可能已經開始殺掉LRU緩存中的其他進程了。你應該釋放那些容易恢復的資源,以便于你的進程可以保留下來,這樣當用戶回退到你的app的時候才能夠迅速恢復。
  • TRIM_MEMORY_MODERATE: 系統(tǒng)正運行于低內存狀態(tài)并且你的進程已經已經接近LRU名單的中部位置。如果系統(tǒng)開始變得更加內存緊張,你的進程是有可能被殺死的。
  • TRIM_MEMORY_COMPLETE: 系統(tǒng)正運行與低內存的狀態(tài)并且你的進程正處于LRU名單中最容易被殺掉的位置。你應該釋放任何不影響你的app恢復狀態(tài)的資源。

因為onTrimMemory()的回調是在API 14才被加進來的,對于老的版本,你可以使用[onLowMemory](http://developer.android.com/reference/android/content/ComponentCallbacks.html#onLowMemory())回調來進行兼容。onLowMemory相當與`TRIM_MEMORY_COMPLETE`。

Note: 當系統(tǒng)開始清除LRU緩存中的進程時,盡管它首先按照LRU的順序來操作,但是它同樣會考慮進程的內存使用量。因此消耗越少的進程則越容易被留下來。

4) 檢查你應該使用多少的內存

正如前面提到的,每一個Android設備都會有不同的RAM總大小與可用空間,因此不同設備為app提供了不同大小的heap限制。你可以通過調用[getMemoryClass()](http://developer.android.com/reference/android/app/ActivityManager.html#getMemoryClass())來獲取你的app的可用heap大小。如果你的app嘗試申請更多的內存,會出現(xiàn)`OutOfMemory`的錯誤。

在一些特殊的情景下,你可以通過在manifest的application標簽下添加largeHeap=true的屬性來聲明一個更大的heap空間。如果你這樣做,你可以通過[getLargeMemoryClass()](http://developer.android.com/reference/android/app/ActivityManager.html#getLargeMemoryClass())來獲取到一個更大的heap size。

然而,能夠獲取更大heap的設計本意是為了一小部分會消耗大量RAM的應用(例如一個大圖片的編輯應用)。不要輕易的因為你需要使用大量的內存而去請求一個大的heap size。只有當你清楚的知道哪里會使用大量的內存并且為什么這些內存必須被保留時才去使用large heap. 因此請盡量少使用large heap。使用額外的內存會影響系統(tǒng)整體的用戶體驗,并且會使得GC的每次運行時間更長。在任務切換時,系統(tǒng)的性能會變得大打折扣。

另外, large heap并不一定能夠獲取到更大的heap。在某些有嚴格限制的機器上,large heap的大小和通常的heap size是一樣的。因此即使你申請了large heap,你還是應該通過執(zhí)行getMemoryClass()來檢查實際獲取到的heap大小。

5) 避免bitmaps的浪費

當你加載一個bitmap時,僅僅需要保留適配當前屏幕設備分辨率的數(shù)據(jù)即可,如果原圖高于你的設備分辨率,需要做縮小的動作。請記住,增加bitmap的尺寸會對內存呈現(xiàn)出2次方的增加,因為X與Y都在增加。

Note:在Android 2.3.x (API level 10)及其以下, bitmap對象的pixel data是存放在native內存中的,它不便于調試。然而,從Android 3.0(API level 11)開始,bitmap pixel data是分配在你的app的Dalvik heap中, 這提升了GC的工作效率并且更加容易Debug。因此如果你的app使用bitmap并在舊的機器上引發(fā)了一些內存問題,切換到3.0以上的機器上進行Debug。

6) 使用優(yōu)化的數(shù)據(jù)容器

利用Android Framework里面優(yōu)化過的容器類,例如SparseArray, SparseBooleanArray, 與 LongSparseArray。 通常的HashMap的實現(xiàn)方式更加消耗內存,因為它需要一個額外的實例對象來記錄Mapping操作。另外,SparseArray更加高效在于他們避免了對key與value的autobox自動裝箱,并且避免了裝箱后的解箱。

7) 請注意內存開銷

對你所使用的語言與庫的成本與開銷有所了解,從開始到結束,在設計你的app時謹記這些信息。通常,表面上看起來無關痛癢(innocuous)的事情也許實際上會導致大量的開銷。例如:

  • Enums的內存消耗通常是static constants的2倍。你應該盡量避免在Android上使用enums。
  • 在Java中的每一個類(包括匿名內部類)都會使用大概500 bytes。
  • 每一個類的實例花銷是12-16 bytes。
  • 往HashMap添加一個entry需要額一個額外占用的32 bytes的entry對象。

8) 請注意代碼“抽象”

通常,開發(fā)者使用抽象作為"好的編程實踐",因為抽象能夠提升代碼的靈活性與可維護性。然而,抽象會導致一個顯著的開銷:通常他們需要同等量的代碼用于可執(zhí)行。那些代碼會被map到內存中。因此如果你的抽象沒有顯著的提升效率,應該盡量避免他們。

9) 為序列化的數(shù)據(jù)使用nano protobufs

Protocol buffers是由Google為序列化結構數(shù)據(jù)而設計的,一種語言無關,平臺無關,具有良好擴展性的協(xié)議。類似XML,卻比XML更加輕量,快速,簡單。如果你需要為你的數(shù)據(jù)實現(xiàn)協(xié)議化,你應該在客戶端的代碼中總是使用nano protobufs。通常的協(xié)議化操作會生成大量繁瑣的代碼,這容易給你的app帶來許多問題:增加RAM的使用量,顯著增加APK的大小,更慢的執(zhí)行速度,更容易達到DEX的字符限制。

關于更多細節(jié),請參考protobuf readme的"Nano version"章節(jié)。

10) 避免使用依賴注入框架

使用類似Guice或者RoboGuice等framework injection包是很有效的,因為他們能夠簡化你的代碼。

Notes:RoboGuice 2 通過依賴注入改變代碼風格,讓Android開發(fā)時的體驗更好。你在調用 getIntent().getExtras() 時經常忘記檢查 null 嗎?RoboGuice 2 可以幫你做。你認為將 findViewById() 的返回值強制轉換成 TextView 是本不必要的工作嗎? RoboGuice 2 可以幫你。RoboGuice 把這些需要猜測性的工作移到Android開發(fā)以外去了。RoboGuice 2 會負責注入你的 View, Resource, System Service或者其他對象等等類似的細節(jié)。

然而,那些框架會通過掃描你的代碼執(zhí)行許多初始化的操作,這會導致你的代碼需要大量的RAM來mapping代碼,而且mapped pages會長時間的被保留在RAM中。

11) 謹慎使用第三方libraries

很多開源的library代碼都不是為移動網絡環(huán)境而編寫的,如果運用在移動設備上,,這樣的效率并不高。當你決定使用一個第三方library的時候,你應該針對移動網絡做繁瑣的遷移與維護的工作。

即使是針對Android而設計的library,也可能是很危險的,因為每一個library所做的事情都是不一樣的。例如,其中一個lib使用的是nano protobufs, 而另外一個使用的是micro protobufs。那么這樣,在你的app里面就有2種protobuf的實現(xiàn)方式。這樣的沖突同樣可能發(fā)生在輸出日志,加載圖片,緩存等等模塊里面。

同樣不要陷入為了1個或者2個功能而導入整個library的陷阱。如果沒有一個合適的庫與你的需求相吻合,你應該考慮自己去實現(xiàn),而不是導入一個大而全的解決方案。

12) 優(yōu)化整體性能

官方有列出許多優(yōu)化整個app性能的文章:Best Practices for Performance。這篇文章就是其中之一。有些文章是講解如何優(yōu)化app的CPU使用效率,有些是如何優(yōu)化app的內存使用效率。

你還應該閱讀optimizing your UI來為layout進行優(yōu)化。同樣還應該關注lint工具所提出的建議,進行優(yōu)化。

13) 使用ProGuard來剔除不需要的代碼

ProGuard能夠通過移除不需要的代碼,重命名類,域與方法等方對代碼進行壓縮,優(yōu)化與混淆。使用ProGuard可以使得你的代碼更加緊湊,這樣能夠使用更少mapped代碼所需要的RAM。

14) 對最終的APK使用zipalign

在編寫完所有代碼,并通過編譯系統(tǒng)生成APK之后,你需要使用zipalign對APK進行重新校準。如果你不做這個步驟,會導致你的APK需要更多的RAM,因為一些類似圖片資源的東西不能被mapped。

Notes: Google Play不接受沒有經過zipalign的APK。

15) 分析你的RAM使用情況

一旦你獲取到一個相對穩(wěn)定的版本后,需要分析你的app整個生命周期內使用的內存情況,并進行優(yōu)化,更多細節(jié)請參考Investigating Your RAM Usage.

16) 使用多進程

如果合適的話,有一個更高級的技術可以幫助你的app管理內存使用:通過把你的app組件切分成多個組件,運行在不同的進程中。這個技術必須謹慎使用,大多數(shù)app都不應該運行在多個進程中。因為如果使用不當,它會顯著增加內存的使用,而不是減少。當你的app需要在后臺運行與前臺一樣的大量的任務的時候,可以考慮使用這個技術。

一個典型的例子是創(chuàng)建一個可以長時間后臺播放的Music Player。如果整個app運行在一個進程中,當后臺播放的時候,前臺的那些UI資源也沒有辦法得到釋放。類似這樣的app可以切分成2個進程:一個用來操作UI,另外一個用來后臺的Service.

你可以通過在manifest文件中聲明'android:process'屬性來實現(xiàn)某個組件運行在另外一個進程的操作。

<service android:name=".PlaybackService"
         android:process=":background" />

更多關于使用這個技術的細節(jié),請參考原文,鏈接如下。 http://developer.android.com/training/articles/memory.html