Android-Application詳解

Vinsmoke_Sanji發表於2018-11-26

Preface

在學習一個SDK的時候,遇到了Application類的相關知識,其實之前也有學習過Application類的一些知識,但是日常開發中使用頻率不高,忘得差不多了.現在重新來總結下Application的使用

英語基礎好的可以去參考官方文件

官方文件

下面是官網對Application類的簡介

Base class for maintaining global application state. You can provide your own implementation by creating a subclass and specifying the fully-qualified name of this subclass as the "android:name" attribute in your AndroidManifest.xml's <application> tag. The Application class, or your subclass of the Application class, is instantiated before any other class when the process for your application/package is created.

大概意思就是Application是用來維護全域性應用狀態的基類.可以通過自己建立子類並且在Manifest.xml檔案中通過name屬性來標記,用來實現自定義的功能.Application類將會在任何類之前例項化

繼承關係

  • Application類繼承自ContextWarpper

下面是示意圖

Android-Application詳解

特點

  • 單例模式:每個App都有且只有一個Application的例項物件(多程式APP除外),可以通過繼承Application子類來進行自定義,如果沒有自定義的話,APP會在開啟是自動建立一個預設的例項物件.

  • 生命週期:APP開啟時就會開始例項化Application物件,Application例項的生命週期是最長的,擁有和APP一樣長的生命週期

  • 獲取方式:如果沒有自定義Application的話,同樣可以獲取到Application物件,使用Activity.getApplication()或者Context.getApplicationContext()方法都可以獲取到物件.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    //這兩種方法都可以獲取到例項物件
    val application = application
    val otherApplication = applicationContext
}
複製程式碼
  • 全域性例項:在不同的元件中(如:Activity,Service),都可以獲取Application物件,並且都會是同一個物件

方法介紹

onCreate()

  • 呼叫時間:

    當應用開啟時,建立應用程式時呼叫此方法.

Tip:這不是Activity的onCreate(),預設是空實現.

  • 使用方式:

    可以用來初始化資料一些全域性變數,物件,也可以用來做一些環境的配置.

  • 演示:

class MyApplication: Application() {
    var whatever = "Whatever"
    
    override fun onCreate() {
        super.onCreate()
        whatever = "Hello"
        //Do something...
    }
}
複製程式碼

註冊ComponentCallback2

  • 簡單說明:

    上面的示意圖中其實還顯示了,Application類是實現了ComponentCallback2介面的,這個介面裡面有三個可以覆寫的方法,可以通過registerComponentCallbacks()方法來進行註冊,也可以使用unregisterComponentCallbacks()來登出.

  • 使用:

override fun onCreate() {
        super.onCreate()
    
        registerComponentCallbacks(object : ComponentCallbacks2 {
            override fun onLowMemory() {

            }

            override fun onConfigurationChanged(newConfig: Configuration?) {

            }

            override fun onTrimMemory(level: Int) {

            }
        })
    }
複製程式碼

onLowMemory()

這是上面ComponentCallback2介面中的方法,用於在Android4.0之前的記憶體檢測,開發者可以在這個回撥方法中做一些優化,防止被系統殺程式.目前用這個方法的情景並不多見,除非開發者想向下相容的比較深.目前可以用onTrimMemory()替代

  • 呼叫時間:監聽到系統記憶體很低的時刻
registerComponentCallbacks(object : ComponentCallbacks2 {
            override fun onLowMemory() {
				//Do something...
            }
        })
複製程式碼

onTrimMemoey()

這個方法目前用來替代上面的onLowMemory()方法.方法會傳入一個level的Int引數,這是一個目前系統通知給App的一個記憶體不足等級,越高越嚴重.不同的等級系統會對App做出不同的操作.

記憶體不足級別 意義
TRIM_MEMORY_RUNNING_MODERATE 等級5:應用可以正常在前臺執行,但是系統已經要開始殺後臺程式了
TRIM_MEMORY_RUNNING_LOW 等級10:應用可以正常在前臺執行,但是系統通知釋放資源,不然會影響速度
TRIM_MEMORY_RUNNING_CRITICAL 等級15:前臺執行,但是大部分後臺被殺死,此時必須釋放記憶體,不然此應用程式也會被殺死
TRIM_MEMORY_UI_HIDDEN 等級20:系統會將該應用的UI資源收回,轉為後臺
TRIM_MEMORY_BACKGROUND 等級40:此時應用處於LRU快取列表的最近位置,需要立刻釋放容易恢復的資源
TRIM_MEMORY_MODERATE 等級60:此時應用處於LRU快取列表的中間位置,有被殺死程式的危險
TRIM_MEMORY_COMPLETE 等級80:非常危險的等級,應用處於快取列表最邊緣,即將被殺死
  • 系統殺程式規則:

    系統會按照LRU Cache列表由低到高殺程式,會優先殺佔用記憶體較高的應用,也就是應用佔用記憶體較小的話,被殺死的概率會降低.

  • 使用方法:

override fun onTrimMemory(level: Int) {
    if (level in TRIM_MEMORY_RUNNING_MODERATE..(TRIM_MEMORY_RUNNING_LOW - 1)){
        //Do something...
    }else if (level >= TRIM_MEMORY_RUNNING_LOW){
		//Do something...
    }
}
複製程式碼

onConfigurationChanged()

  • 作用:

    監聽APP的一些配置資訊的改變事件(比如螢幕旋轉)

  • 呼叫時間:

    當配置資訊改變的時候會回撥此方法

  • 配置資訊:

    配置資訊也就是Manifest.xml檔案中Activityandroid:configChanges屬性的值,在該屬性中填入android:configChanges="keyboardHidden|orientation|screenSize"可以讓螢幕旋轉時不重啟,而是執行onConfigurationChanged()方法

  • 使用方法:

registerComponentCallbacks(object : ComponentCallbacks2 {
    override fun onConfigurationChanged(newConfig: Configuration?) {
		//Do something
    }
}
複製程式碼

ActivityLifecycleCallbacks()

這是一個介面,可以通過registerActivityLifecycleCallbacks()unregisterActivityLifecycleCallbacks()來註冊/登出對所有Activity生命週期的監聽,當Activity的生命週期發生改變的時候,就會呼叫介面裡的方法.

  • 使用方法
registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
            override fun onActivityPaused(activity: Activity?) {

            }

            override fun onActivityResumed(activity: Activity?) {

            }

            override fun onActivityStarted(activity: Activity?) {

            }

            override fun onActivityDestroyed(activity: Activity?) {

            }

            override fun onActivitySaveInstanceState(activity: Activity?, outState: Bundle?) {

            }

            override fun onActivityStopped(activity: Activity?) {

            }

            override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) {

            }
        })
複製程式碼

這個主要就是對不同的生命週期進行監聽,這裡就不往裡面寫操作程式碼了.有興趣的可以自己在裡面加Log測試.

onTerminate()

在程式結束的時候會呼叫,只是用於模擬機的測試,真機上不會呼叫,沒什麼好說的.

registerOnProvideAssistDataListener()&unregisterOnProvideAssistDataListener()

這兩個方法看名字是需要可以註冊準備語音助手的資料的監聽器,需要傳入OnProvideAssistDataListener介面物件,介面裡只有一個onProvideAssistData(Activity activity,Bundle data)的方法,看官網的介紹是當使用者啟動語音助手時會構建一個Intent.ACTION_ASSIST.而且會附加使用者請求幫助時的使用者位置資訊和上下文.

Android-Application詳解

看網上的說法是國外的手機呼叫語音助手是會呼叫這個方法,我猜測應該不是國外手機,而是谷歌的語音助手,我用OxygenOS系統測試了一下,發現確實在撥出谷歌助手的時候呼叫了方法,Bundle不是空的,但是我也沒找到裡面的資訊,應該是我的方法不對,我目前還沒探究出這個方法要怎麼用.如果有知道的大牛麻煩指導一下

  • 我的測試:
registerOnProvideAssistDataListener { activity, data ->
         if (data == null) {
             Log.d("日誌", "Bundle為空")
         } else {
             var string = "Bundle{"
             for (item in data.keySet()) {
                 string += " $item => ${data.get(item)};"
             }
             string += "}Bundle"
             Log.d("日誌",string)
             Log.d("日誌","data is:$ACTION_ASSIST + $EXTRA_ASSIST_PACKAGE + $EXTRA_ASSIST_CONTEXT")
             startActivity(object :Intent(ACTION_ASSIST){})
         }
}
複製程式碼
  • 測試結果:
日誌: Bundle{}Bundle
日誌: data is:android.intent.action.ASSIST + android.intent.extra.ASSIST_PACKAGE + android.intent.extra.ASSIST_CONTEXT
複製程式碼

自定義Application

介紹完上面的方法,現在總算要開始自定義Application類了,其實自定義Application類步驟並不多,下面來介紹一下.

  • 建立繼承自Application類的子類

    這個就沒什麼說的了,直接看程式碼吧

class MyApplication : Application() {

    override fun onCreate() {
        super.onCreate()
		//DO something...
    }
}
複製程式碼
  • 進入Manifest配置自定義類
<application
         android:name=".MyApplication"            
</application>
複製程式碼
  • 獲取Application類的例項

    獲取例項的方法上面已經講到了,這裡就不贅述了.

作用

一般來說是不需要自定義Application類的,但是如果需要實現下面的功能,可以自定義Application類

  • 初始化部分資源(全域性物件,全域性共享變數,方法等)
  • 對記憶體佔用進行優化
  • 監聽APP配置資訊和所有Activity的生命週期