編輯:關於Android編程
以前在網上也看過類似的譯文,但也忘得差不多了. 直至最近在官網再次看到原文, 雖是09年的文章, 略顯久遠, 但再看一次還是覺得總結很好. 於是決定翻譯下來, 順便鞏固自己的相關知識.
原文鏈接
安卓應用在大多數機型( 針對以前的比較舊的機型, 現在的手機配置越來越高, 可分配的運行內存也相應會比以前提高) 會得到16MB的應用內存. 即使你不打算真的使用這全部的內存, 你也應該盡可能的使用更少的內存, 以免因為占用內存過大而進程被系統殺死. Android手機內存中(短暫)保留的應用更多, 那麼用戶在這些被保留的應用間互相切換時就會更快(得到響應). 工作中, 碰到內存洩露問題是會碰到的情況, 並且這種情況大多數都是因為時間過長的( 對象,資源等 )引用存在於應用上下文(Context)中.
在Android中, 一個Context被用於很多的操作中, 但大多數是用於加載和使用資源, 這也是為什麼所有組件(Widgets)在構造器中都需要接收一個Context參數. 在一般的Android應用中, 你通常會擁有2種Context, Activity和 Applicatin. 這也通常是開發人員首先要傳到類和方法中的Context:
@Override protected void onCreate(Bundle state) { super.onCreate(state); TextView label = new TextView(this); label.setText("Leaks are bad"); setContentView(label); }
這意味著, 視圖(Views)有一個在整個Activity中的引用, 也因此該Activity會(緊緊)保持這些Views: 通常是整個View所有層級的父View和子View,以及這些View所用到的資源. 因此, 如果你洩露(leak)了上下文(Context).(這裡的"洩露" 是指你保持了一個避免被GC - 垃圾回收機制回收 的引用 ), 逐漸的會變成洩露了很多內存. 這樣下去, 如果你稍不注意, 洩露一整個Activity的內存是很容易發生的事情.
當屏幕橫豎屏切換, 系統會默認銷毀當前Activity, 然後會根據舊Activity被銷毀前被保存的狀態(要開發者在銷毀前手動保存狀態才有效)去創建一個新的Activity. 這樣, Android將會重載應用的UI布局和資源的. 現在你不想應用在每一個方向(豎屏, 橫屏)都加載一個大的位圖(bitmap). 那麼保持這個位圖, 不在每次倒置屏幕時都去重載它的最簡單的方法就是將它設為靜態(static):
private static Drawable sBackground; @Override protected void onCreate(Bundle state) { super.onCreate(state); TextView label = new TextView(this); label.setText("Leaks are bad"); if (sBackground == null) { sBackground = getDrawable(R.drawable.large_bitmap); } label.setBackgroundDrawable(sBackground); setContentView(label); }
這個代碼塊運行起來的確很快, 但也非常錯誤; 它會導致在屏幕倒置變換而被創建的第一個Activity內存洩露. 當一個 Drawable 在View中被使用, View 會被設置一個Drawable的回調. 在上面的代碼塊中, 這個意味著drawable在TextView中有一個應用, 而這個TextView本身在Activity(上下文)中又有一個引用. 類似這樣, Activity就保持著各種資源的引用(當然這取決於你的代碼).
這是其中一個最簡單的洩露上下文(Context)內存的例子, 你能在這裡( 在主屏幕源碼 Home screen's source code 查找 unbindDrawables()方法
)看到它是怎麼工作的. 當Activity被銷毀時, 將(引用的)存儲的drawable回調為null. 有趣的是, 在某些你創建了資源間互相引用的"鏈"的情況下這麼做是不好的, 反而使應用更快的耗盡內存.
這裡有2個簡單的方法去避免相關的上下文內存洩露. 最顯著的一個方法是避免資源脫離自身所在的上下文范圍(而存在). 上面的例子展示了靜態引用的案例, 內部類和該類包含的引用對其他類可能是同樣的危險. 第二個解決方案是是適用 Application
這個上下文對象. Application 會一直在應用運行時存在, 並且不會像Activity受其生命周期影響. 如果你打算保持一個長期使用的對象, 就需要一個這樣的上下文(Context). 你可以輕易的通過調用 Context.getApplicationContext() 和 Activity.getApplication() 方法來獲得它.
總結, 為了避免相關上下文洩露內存, 請記得以下的幾點:
我從去年開始使用 RxJava ,到現在一年多了。今年加入了 Flipboard 後,看到 Flipboard 的 Android 項目也在使用 RxJava ,並且使用
在Android開發中,我們常用的布局方式主要有LinearLayout、RelativeLayout、FrameLayout等,通過這些布局我們可以實現各種各樣的界面。
概述這篇文章是深入掌握自定義LayoutManager系列的開篇,是一份總結報告。部分內容不屬於引言、過於深入,用作系列後續文章的參考,以及浏覽完後的復習之用。本文內容涉
引言布局是直接影響用戶體驗的關鍵部分。如果實現的不好,那麼布局很有可能會導致內存的緊張。Android的SDK包含的一些工具可以用來檢查布局性能上的問題。結合本章的課程學