1. 程式人生 > >Application類學習總結

Application類學習總結

一、Application繼承關係:Application extends ContextWrapper implements ComponentCallbacks2

1、ContextWrapper繼承關係:ContextWrapper extends Context,從類名上理解即是對Context類的包裝。

原始碼註釋:Proxying implementation of Context that simply delegates(代理或代表) all of its calls to another Context.  Can be subclassed to modify behavior without changing the original Context.

說明:在ContextWrapper類中,只有唯一的一屬性Context mBase,事實上在ContextWrapper中所有方法都是圍繞著mBase做封裝,提供一系列供外部使用的get和set等方法,個人認為google這一做法旨在降低呼叫者使用Context的難度。

2、ComponentCallbacks2繼承關係:extends ComponentCallbacks,

原始碼註釋:Extended ComponentCallbacks interface with a new callback for finer-grained memory management.只新增了void onTrimMemory(int level)抽象方法,字面意思是修剪記憶體,該介面主要是依據不同的級別來回收記憶體。因此,ComponentCallbacks2介面的作用就是讓開發者在適當時機修剪釋放記憶體。

3、ComponentCallbacks:最上層介面,只包含兩個抽象方法:
(1)void onConfigurationChanged(Configuration newConfig):當元件在執行時配置發生了改變該介面就會回撥。(如螢幕方向、鎖屏)

(2)void onLowMemory():當系統記憶體不足時或者程式所在的程序應該釋放記憶體時會回撥該方法

二、Application構造方法:

public Application() {
     super(null);
}

說明:目前只分析了使用Instrumentation框架時Application的構造過程,流程是大概是這樣的:
1、首先在Androidmanifest的<application>聲明瞭android:name=".app.ManifestApplication"屬性之後,經過xml解析,獲取到Application完整類名;
2、接著由Instrumentation類的newApplication方法通過反射的方式來例項化Application。

public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        return newApplication(cl.loadClass(className), context);
    }


static public Application newApplication(Class<?> clazz, Context context) throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        Application app = (Application)clazz.newInstance();
        app.attach(context);
        return app;
    }
3、例項化app之後馬上就會執行attach方法,注意這個attach方法是個隱藏方法,在這個方法中又會呼叫父類ContextWrapper的attachBaseContext方法
final void attach(Context context) {
        attachBaseContext(context);
        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
    }
4、執行ContextWrapper的attachBaseContext方法,真正為mBase屬性賦值。
protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }

5、只有執行了app.attach(context)方法之後,Application的例項化工作才算完成,且最關鍵的一步是為mBase重新賦值。

三、Application的內部介面:在Application中定義了ActivityLifecycleCallbacks和OnProvideAssistDataListener兩個介面。
1、ActivityLifecycleCallbacks介面:Activity生命週期方法的回撥介面,需要注意的是該回調方法是在Activity類中回撥的,且在Activity類的不同的生命週期方法中各自的回撥時機是不一樣的,有可能是在生命週期方法開始執行或執行結束的時候才回調,但是對於Activity實現類來說,都在super.onXXX()中回撥,因此Activity實現類的ActivityLifecycleCallbacks回撥時機取決於各自生命週期方法中的super.onXXX()的呼叫時機,而不一定在生命週期方法的開始或結束時呼叫。

public interface ActivityLifecycleCallbacks {
        void onActivityCreated(Activity activity, Bundle savedInstanceState);
        void onActivityStarted(Activity activity);
        void onActivityResumed(Activity activity);
        void onActivityPaused(Activity activity);
        void onActivityStopped(Activity activity);
        void onActivitySaveInstanceState(Activity activity, Bundle outState);
        void onActivityDestroyed(Activity activity);
    }

2、OnProvideAssistDataListener介面:該介面是API18的新增介面,主要是用於助手應用與本應用的資料互動介面,使用本介面需要在Application實現類中進行在註冊與登出。

public interface OnProvideAssistDataListener {
        /**
         * This is called when the user is requesting an assist, to build a full
         * {@link Intent#ACTION_ASSIST} Intent with all of the context of the current
         * application.  You can override this method to place into the bundle anything
         * you would like to appear in the {@link Intent#EXTRA_ASSIST_CONTEXT} part
         * of the assist Intent.
         */
        public void onProvideAssistData(Activity activity, Bundle data);
    }

四、Application的成員變數:只有四個成員變數,其中三個是Callbacks型別的列表資料。
1、private ArrayList<ComponentCallbacks> mComponentCallbacks = new ArrayList<ComponentCallbacks>(); 所有元件都可能觸發該回調介面
2、private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks = new ArrayList<ActivityLifecycleCallbacks>();只有Activity元件會觸發該介面;
3、private ArrayList<OnProvideAssistDataListener> mAssistCallbacks = null;由助手應用觸發該介面;
4、public LoadedApk mLoadedApk:apk載入類,注意該屬性是一隱藏屬性,只供內部api使用,是從ContextImpl類中獲取獲取其例項。如下
	mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;

五、Application的方法:主要分為公有方法、包訪問方法以及私有方法
1、公有方法:Application的實現類都可以重寫這些方法,如onCreate、onTerminate等
(1)其中的三個Callbacks型別的成員變數就對應的各自的registerXXCallbacks和unregisterXXCallbacks兩個方法,注意是成對出現,忘記unregisterXXCallbacks有可能出現記憶體洩漏的風險,比如使用registerActivityLifecycleCallbacks方法,其回撥介面是帶有activity這一引數的,在activity被執行完生命週期方法時,按理應該是被虛擬機器回收的,但是因為這個回撥的存在導致不能進行回收,從而出現記憶體洩漏。(當然還未測試)
(2)onCreate方法:當application啟動時,就會去執行,單單看這個類還不知道是由誰去觸發該方法,它先於activity、service和receiver的create方法執行,但是不包括ContentProvider,經驗證ContentProvider的oncreate方法確實先於application。當子類重寫該方法時,google建議應儘可能減少該方法的執行時間,即不要做什麼耗時操作,否則會直接影響第一個Activity啟動的時間。
(3)onTerminate方法:該方法是在模擬器執行環境下才會被回撥的,在android裝置上僅僅簡單的kill吊進行時該方法並不會被回撥,因此不建議在該回調方法
中實現業務相關的程式碼。
(4)onConfigurationChanged和onLowMemory方法:都是來自ComponentCallbacks介面,當裝置的屬性如系統字型、螢幕方向改變時,會觸發該方法
(5)onTrimMemory方法:來自ComponentCallbacks2介面,google提供的用於回收記憶體的方法。(將在activity篇中總結)

2、而包訪問方法是被同級包內所呼叫的,起著橋樑的作用,主要是收集來自上層的介面回撥資訊以及Activity生命週期回撥事件的分發方法。

(1)attach方法:前面已經提及,是由Instrumentation類的newApplication方法所呼叫。
(2)dispatchActivityXX方法:這類方法是由Activity類來呼叫,需要注意的是Activity類中各個生命週期方法的呼叫時機是不一樣的,但是大多數都是在生命週期方法的末尾或靠近末尾的時候執行呼叫,從這個層面來講可以理解為:只要出現回撥,那麼Activity類(注意不是其子類)中各個生命週期方法已經執行完畢了。
3、私有方法作用就是被類中的其他非私有方法服務,在這類中只有兩個方法:collectComponentCallbacks和collectActivityLifecycleCallbacks方法。