安卓APP實戰(二):Activity管理,內存回收及LeakCanary監測

每一個Activity組件都是一個單獨的界面,承載着與用戶交互的任務。也是應用最基本的功能之一,在不同界面之間切換,並實現不同的功能。
每一個程序必須要有一個Activity作爲入口(Manifest文件中將其<category>標籤設置爲LAUNCHER),然後通過界面控制到達其他的界面。

Activity是具有生命週期的,在不同生命週期會執行其中回調方法。所有的方法在自己的Activity中可以進行重寫。安卓中添加新的Activity可以通過AS進行選擇新建不同的類型,以減少部分代碼量。

下面的文章中對Activity做了不錯的介紹。並通過簡單的LOG打印日誌可以清晰看到各執行Activity和切換Activity的執行順序。
參考:https://www.cnblogs.com/caobotao/p/4987015.html

配合下面官方給的生命週期圖,對Activity做一個初步的理解。
1.當我們打開一個Activity,執行onCreated方法,進入created(已創建)狀態,這時候大概會去內存中將Activity類需要的資源全部申請成功。
2.第二步會接着執行onStart方法,進入started(已啓動)狀態。這時候我們便可以看到這個界面,但是是無法進行操作的,這時候整個界面已經渲染完成。
3.第三步執行onResume方法,進入resumed(Resume有重新開始,繼續的意思,然而在第一次創建時並沒有繼續,重新,所以個人認爲用focused(已獲取焦點)或running(運行中)似乎更恰當)狀態,此時獲取了應用的焦點,我們才能對界面進行操作,至此Activity纔算是正常的啓動並提供服務了,若沒有其他操作應用將保持此狀態。

以上三步是Activity創建後固定順序執行的步驟對應三個狀態。在圖片中有個狀態轉換需要調用的方法名,可以認爲調用控制Activity的生命狀態。
4.paused(暫停)狀態。官方定義是partially visible(部分可見)。即界面被遮擋了,並且未全部遮擋,比如一些彈框等。此時遮擋界面將會獲得應用的焦點,而原本的界面失去焦點無法操作,此時界面顯示的渲染依然都在。
5.stopped(停止)狀態。官方定義是hidden(隱藏的)。當界面被完全覆蓋時,前臺渲染已經銷燬了,只有內存中Activity的對象等還存在。
6.Destroyed(已銷燬的)狀態。銷燬的執行大致有三種情況:1.系統內存不足時自動銷燬停止,暫停狀態的Activity. 2.調用finish()方法。銷燬時會根據當前狀態順序執行 onPause()->onStop->onDestroy(),如處於stopped狀態就只調用onDestroy。

對於Activity的生命週期必須進行管理,否則很容易發生OOM(Out of memory)的異常。比如頻繁切換(startActivity()方法),10次左右就會發生OOM,導致程序奔潰(模擬器會停止運行,使用真機調試會報錯,到不影響程序運行)。

在這裏插入圖片描述

Activity界面切換使用方法startActivity (Intent intent)。
基本的寫法就是 startActivity(new Intent(ActivityBefore.this, ActivityAfter.class)); ActivityBefore就是切換前的Activity類,ActivityAfter是切換後的目標Activity類。

在進行Activity切換時需要對Activity生命週期進行管理避免造成OOM。在不再需要使用的Activity中調用finish函數,銷燬並收回佔用的內存及資源。

需求中數字選擇界面可以選擇1到9,選擇進入書寫界面,書寫界面有返回按鈕,點擊後調用startActivity切換回數字選擇界面。此時若進入數字1書寫界面,然後返回數字選擇界面,然後重複選擇剩餘數字切換界面,在切換第九個數字時便會出現OOM異常。內存情況如下。每次新點開一個數字書寫界面,內存會不斷被佔用而不被釋放,最終導致內存溢出。
在這裏插入圖片描述

因爲從數字書寫界面返回後,我們可以認爲此界面不會再被使用,因爲此界面沒有任何信息需要儲存,重新選擇進入時我們只需要重新創建即可,此時避免Activity切換造成的內存溢出可以做兩種處理:

1.在調用startActivity進行切換後,調用finish()函數,將不需要使用的Activity銷燬,此時會根據Activity當前狀態去選擇執行pause,stop,destroy函數,如處於stopped狀態就只調用onDestroy。。
2.若使用手機自帶返回事件,如返回鍵,觸發後會順序執行pause,stop,destroy三個函數,對Activity進行銷燬。

安卓使用任務棧管理Activity,startActivity的作用是將另一個Activity放置到棧頂,當前Activity並未銷燬,而是位於棧頂第二位,此時按下返回鍵便可以重回棧頂。而使用finish(),則會將其移出棧,按下返回鍵也無法返回。

參考:https://www.cnblogs.com/whieenz/p/8047139.html

管理Activity時,還需要注意Activity中對象的回收,如bitmap,thread,handler等等,避免Activity無法被正常回收。
此部分內容還未細究
可參考:https://blog.csdn.net/chen825919148/article/details/23843049

爲了很好的監測內存溢出的情況,使用LeakCanary進行監測。而其使用也非常簡單。

1.在Module的build.gradle文件中增加依賴包,此時要重新build項目。

	dependencies {
		.......//其他依賴包
		debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.4'
   	 	releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
   	 }

2.自定義Application類。
若LeakCanary引用有問題,則build發生異常,嘗試重新build即可,使用就只要在1中添加依賴就可以,不需要其他任何操作。自定義Application類後,在Manifest文件中<application>標籤中的 android:name 屬性 更改爲自定義類,如 android:name=“com.example.wangjy.application.App”

import com.squareup.leakcanary.LeakCanary;
import com.squareup.leakcanary.RefWatcher;

	public class App extends Application {

    private RefWatcher refWatcher;

    @Override
    public void onCreate() {
        // 程序創建的時候執行
        super.onCreate();
        refWatcher = LeakCanary.install(this);
    }
   
    public static RefWatcher getRefWatcher(Context context){
        App application = (App)context.getApplicationContext();
        return application.refWatcher;
    }
}

3.進行調用
在需要監測的Activity中增加

RefWatcher refWatcher = App.getRefWatcher(this);
        refWatcher.watch(this);

爲了方便使用,可以使用繼承,在父類中進行監測。

最後關於Activity之間的參數傳遞。
最常用最基本的就是基本數據類型的傳遞。
使用intent傳遞即可。
在調用startActivity之前,先使用intent.putExtra(key,value)設置傳遞的參數。key是參數名,value是參數值。如(“what”,“abcd”)
在接收參數時,調用getIntent().get + 數據類型+ Extra(key)
如:
SelectActivity(跳轉前,發送方)中

Intent goWrite = new Intent(SelectActivity.this, WriteActivity.class);
            goWrite.putExtra("num", num);
            startActivity(goWrite);

WriteActivity(跳轉後,接收方)中

num = getIntent().getIntExtra("num", -1);

參考:https://www.cnblogs.com/icyhusky/p/5964756.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章