1. 程式人生 > >Android中的Context類簇(裝飾模式)及Context用法詳解,Application用法詳解

Android中的Context類簇(裝飾模式)及Context用法詳解,Application用法詳解

一,Context類簇中的類概述

Context的API文件
這裡寫圖片描述
類關係:
這裡寫圖片描述

Context類

Context是一個抽象類,原始碼位於android.content包中。描述的是一個應用程式環境的資訊,即上下文。通過它我們可以獲取應用程式的資源和類,也包括一些應用級別操作,例如:啟動一個Activity,傳送廣播,接受Intent資訊 ,得到各種服務(getSystemService)等。在下面再詳細說說。

ContextImpl類

ContextImpl是Context抽象類另一個直接子類,有一個私有的構造方法。原始碼位於android.app包中,但它在API文件中找不到,是一個預設訪問許可權的類,也就是說它只允許android.app包中的類可以呼叫它,或者只有和它同包的類才可以通過其父類的方法使用它。它是Context抽象類的具體實現,也是說Context抽象類中抽象方法在ContextImpl類中都有實現,比如:

@Override
    public void startActivity(Intent intent, Bundle options) {
        warnIfCallingFromSystemProcess();
        if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
            throw new AndroidRuntimeException(
                    "Calling startActivity() from outside of an Activity "
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag." + " Is this really what you want?"); } mMainThread.getInstrumentation().execStartActivity( getOuterContext(), mMainThread.getApplicationThread(), null, (Activity) null
, intent, -1, options); }

同時,ContextImpl類又通過自己的成員變數mOuterContext來引用了與它關聯的一個Activity元件,這樣,ContextImpl類也可以將一些操作轉發給Activity元件來處理。請注意,該函式的大部分功能都是直接呼叫其類成員mPackageInfo來完成。

ContextWrapper類

ContextWrapper也是Context抽象類直接子類,是其包裝類,也位於android.app中,在其類中聲明瞭一個Context引用mBase,指向一個ContextIml例項,一般在建立Application、Service、Activity時賦值,構造方法:

Context mBase;
    public ContextWrapper(Context base) {
        mBase = base;
    }

Wrapper是包裝的意思,表示其是對Context類進行了包裝的一個類,它把Context類的方法都類似如下的形式進行了重寫:

@Override
    public void startActivity(Intent intent) {
        mBase.startActivity(intent);
    }
@Override
    public ComponentName startService(Intent service) {
        return mBase.startService(service);
    }

如果重寫的是沒返回值,則直接呼叫父類的此方法;如果重寫的有返回值,則返回呼叫父類返回的值。

因為ContextWrapper類和ContextImpl類處於同一包中,所以當呼叫ContextWrapper類中方法時,無論是通過Context呼叫,還是在ContextWrapper的子類中呼叫(如果子類重寫沒super就不會呼叫ContextWrapper類中方法了),最終都是呼叫ContextImpl類中的同名方法。比如啟動Activity,在Activity裡啟動,呼叫的是Activity類裡重寫的 startActivity(),如果是在Service裡啟動,呼叫的就是ContextImpl類中的 startActivity()。這種模式是裝飾模式,Context是抽象構件類,ContextImpl類是具體構件類,ContextWrapper類是抽象裝飾類。後面附上有裝飾模式的介紹。

MockContext類

MockContext也是Context的子類,Mock以為模擬,假裝,嘲笑,這裡可以理解為模擬Context,原始碼位於 android.test.mock包中,API文件中找不到。類中的方法都類似如下:

@Override
    public void startActivity(Intent intent) {
        throw new UnsupportedOperationException();
    }

當我們要測試一個模組A,他依賴與其它模組B,但是模組B還沒實現或現在根本沒有,這時就要使用MockContext和其他同樣位於android.test.mock包中的類。通過它可以注入其他依賴,模擬Context,或者監聽測試的類。用法參考Mock在Android TDD中的使用

Application類

Application繼承自ContextWrapper,是維持全域性應用狀態的基類,位於android.app包中。它還實現了ComponentCallbacks2,實現此介面的有Activity,Service,Content Provider,Fragment,Application及其子類,這個介面作用是細化記憶體管理,其對所有應用元件都非常有用。其構造方法為:

public Application() {
        super(null);
    }

在無參的構造方法中呼叫了父類的構造方法,向父類構造方法傳的值為null。

其有兩個子類MultiDexApplication,是multidex 需要用到的 ;MockApplication,和MockContext作用類似。

backupAgent類

Android:backupAgent用來設定備份代理。對於大部分應用程式來說,都或多或少儲存著一些永續性的資料,比如資料庫和共享檔案,或者有自己的配置資訊。為了保證這些資料和配置資訊的安全性以及完整性,Android提供了這樣一個機制。
詳細參考backupAgent的用法

ContextThemeWrapper類

ContextThemeWrapper繼承自ContextWrapper,位於android.view包中,該類內部包含了主題(Theme)相關的介面,即android:theme屬性指定的。構造方法如下:

public ContextThemeWrapper() {
        super(null);
    }

    public ContextThemeWrapper(Context base, @StyleRes int themeResId) {
        super(base);
        mThemeResource = themeResId;
    }

    public ContextThemeWrapper(Context base, Resources.Theme theme) {
        super(base);
        mTheme = theme;
    }

MutableContextWrapper類

MutableContextWrapper繼承自ContextWrapper, 位於包android.content中,是ContextWrapper的特別版,在其初始化設定後修改他的基礎上下文。很少用到,其只有一個公共方法setBaseContext(),關於什麼是BaseContext在下面會有解釋。

其他類

IsolatedContext和RenamingDelegatingContext在Api24被棄用,這裡就不介紹了。Service和Application的類繼承關係比較像,而Activity還多了一層繼承ContextThemeWrapper,這是因為Activity有主題的概念,而Service是沒有介面的服務。然後下面就著重說說Context和Application。

二,Context

Context是上下文,代表的是執行的環境,它的實現為ContextImpl,是應用執行中自動建立的。應用在三種情況下會建立Context物件(即通常說的context):
1> 建立Application 物件時,即第一次啟動app時。 整個App共一個Application物件,所以也只有一個Application 的Context,Application銷燬,它也銷燬;
2> 建立Activity物件時。Activity銷燬,它也銷燬;
3> 建立Service物件時。Service銷燬,它也銷燬。

由此可以得到應用程式App可以建立的Context(Activity和Service沒啟動就不會建立)個數公式一般為:
總Context例項個數 = Service個數 + Activity個數 + 1(Application對應的Context物件)
Context物件的建立推薦閱讀Android中Context詳解

Context類中常用的方法

Context類中常用的方法有:


// 獲取應用程式包的AssetManager例項
public abstract AssetManager getAssets();

// 獲取應用程式包的Resources例項
public abstract Resources getResources();

// 獲取PackageManager例項,以檢視全域性package資訊
public abstract PackageManager getPackageManager();

// 獲取應用程式包的ContentResolver例項
public abstract ContentResolver getContentResolver();

// 它返回當前程序的主執行緒的Looper,此執行緒分發呼叫給應用元件(activities, services等)
public abstract Looper getMainLooper();

// 返回當前程序的單例項全域性Application物件的Context
public abstract Context getApplicationContext();

// 從string表中獲取本地化的、格式化的字元序列
public final CharSequence getText(int resId) {
return getResources().getText(resId);
}

// 從string表中獲取本地化的字串
public final String getString(int resId) {
return getResources().getString(resId);
}

public final String getString(int resId, Object... formatArgs) {
return getResources().getString(resId, formatArgs);
}

// 返回一個可用於獲取包中類資訊的class loader
public abstract ClassLoader getClassLoader();

// 返回應用程式包名
public abstract String getPackageName();

// 返回應用程式資訊
public abstract ApplicationInfo getApplicationInfo();

// 根據檔名獲取SharedPreferences
public abstract SharedPreferences getSharedPreferences(String name,
int mode);

// 其根目錄為: Environment.getExternalStorageDirectory()
/*
* @param type The type of files directory to return.  May be null for
* the root of the files directory or one of
* the following Environment constants for a subdirectory:
* {@link android.os.Environment#DIRECTORY_MUSIC},
* {@link android.os.Environment#DIRECTORY_PODCASTS},
* {@link android.os.Environment#DIRECTORY_RINGTONES},
* {@link android.os.Environment#DIRECTORY_ALARMS},
* {@link android.os.Environment#DIRECTORY_NOTIFICATIONS},
* {@link android.os.Environment#DIRECTORY_PICTURES}, or
* {@link android.os.Environment#DIRECTORY_MOVIES}.
*/
public abstract File getExternalFilesDir(String type);

// 返回應用程式obb檔案路徑
public abstract File getObbDir();

// 啟動一個新的activity
public abstract void startActivity(Intent intent);

// 啟動一個新的activity
public void startActivityAsUser(Intent intent, UserHandle user) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}

// 啟動一個新的activity
// intent: 將被啟動的activity的描述資訊
// options: 描述activity將如何被啟動
public abstract void startActivity(Intent intent, Bundle options);

// 啟動多個新的activity
public abstract void startActivities(Intent[] intents);

// 啟動多個新的activity
public abstract void startActivities(Intent[] intents, Bundle options);

// 廣播一個intent給所有感興趣的接收者,非同步機制
public abstract void sendBroadcast(Intent intent);

// 廣播一個intent給所有感興趣的接收者,非同步機制
public abstract void sendBroadcast(Intent intent,String receiverPermission);
//傳送有序廣播
public abstract void sendOrderedBroadcast(Intent intent,String receiverPermission);

public abstract void sendOrderedBroadcast(Intent intent,
String receiverPermission, BroadcastReceiver resultReceiver,
Handler scheduler, int initialCode, String initialData,
Bundle initialExtras);

public abstract void sendBroadcastAsUser(Intent intent, UserHandle user);

public abstract void sendBroadcastAsUser(Intent intent, UserHandle user,
String receiverPermission);

// 註冊一個BroadcastReceiver,且它將在主activity執行緒中執行
public abstract Intent registerReceiver(BroadcastReceiver receiver,
IntentFilter filter);
//取消註冊BroadcastReceiver
public abstract Intent registerReceiver(BroadcastReceiver receiver,
IntentFilter filter, String broadcastPermission, Handler scheduler);

public abstract void unregisterReceiver(BroadcastReceiver receiver);

// 請求啟動一個application service
public abstract ComponentName startService(Intent service);

// 請求停止一個application service
public abstract boolean stopService(Intent service);

// 連線一個應用服務,它定義了application和service間的依賴關係
public abstract boolean bindService(Intent service, ServiceConnection conn,
int flags);

// 斷開一個應用服務,當服務重新開始時,將不再接收到呼叫,
// 且服務允許隨時停止
public abstract void unbindService(ServiceConnection conn);

// 返回系統級service
/*
* @see #WINDOW_SERVICE
* @see android.view.WindowManager
* @see #LAYOUT_INFLATER_SERVICE
* @see android.view.LayoutInflater
* @see #ACTIVITY_SERVICE
* @see android.app.ActivityManager
* @see #POWER_SERVICE
* @see android.os.PowerManager
* @see #ALARM_SERVICE
* @see android.app.AlarmManager
* @see #NOTIFICATION_SERVICE
* @see android.app.NotificationManager
* @see #KEYGUARD_SERVICE
* @see android.app.KeyguardManager
* @see #LOCATION_SERVICE
* @see android.location.LocationManager
* @see #SEARCH_SERVICE
* @see android.app.SearchManager
* @see #SENSOR_SERVICE
* @see android.hardware.SensorManager
* @see #STORAGE_SERVICE
* @see android.os.storage.StorageManager
* @see #VIBRATOR_SERVICE
* @see android.os.Vibrator
* @see #CONNECTIVITY_SERVICE
* @see android.net.ConnectivityManager
* @see #WIFI_SERVICE
* @see android.net.wifi.WifiManager
* @see #AUDIO_SERVICE
* @see android.media.AudioManager
* @see #MEDIA_ROUTER_SERVICE
* @see android.media.MediaRouter
* @see #TELEPHONY_SERVICE
* @see android.telephony.TelephonyManager
* @see #INPUT_METHOD_SERVICE
* @see android.view.inputmethod.InputMethodManager
* @see #UI_MODE_SERVICE
* @see android.app.UiModeManager
* @see #DOWNLOAD_SERVICE
* @see android.app.DownloadManager
*/
public abstract Object getSystemService(String name);
//檢查許可權
public abstract int checkPermission(String permission, int pid, int uid);

// 返回一個新的與application name對應的Context物件
public abstract Context createPackageContext(String packageName,
int flags) throws PackageManager.NameNotFoundException;

// 返回基於當前Context物件的新物件,其資源與display相匹配
public abstract Context createDisplayContext(Display display);

Context其主要功能如下:

啟動Activity
啟動和停止Service
傳送廣播訊息(Intent)
註冊廣播訊息(Intent)接收者
可以訪問APK中各種資源(如Resources和AssetManager等)
可以訪問Package的相關資訊
APK的各種許可權管理

Context幾乎算是對APK包無所不知的大管家,大家需要什麼,Context子類裡(通常在Activity和Service)直接呼叫就可以了。

獲取Context

public class MyActivity extends Activity {
    Context mContext;
    public void method() {

        mContext = this; //獲取當前Activity的上下文,如果需要繫結Activity的生命週期,使用它

        mContext=MyActivity.this;//獲取當前MyActivity的上下文,不方便使用this的時候推薦使用這種方式

        //呼叫Activity.getApplicationContext()
        mContext = getApplicationContext();//獲取當前Application的上下文,如果需要繫結應用的生命週期,使用它

        //Activity.getApplication()
        mContext = getApplication();//獲取當前Application的上下文,

        //呼叫ContextWrapper.getBaseContext()
        mContext = getBaseContext();//從上下文A內上下文訪問上下文A,不建議使用,如果需要,推薦使用XxxClass.this直接指出上下文
    }
}
public class MyView extends View {
    Context mContext;
    public void method() {

        //呼叫View.getContext()
        mContext = getContext(); //獲取這個View執行所在地的上下文
    }
}

關於this和getBaseContext()

Activity和Application直接父類是 ContextWrapper,而不是Context,ContextWrapper.getBaseContext()最終呼叫的是ContextImpl.getBaseContext(),它和this雖然都可以代表Activity的Context,但指向的並不是同一個物件(this != getBaseContext()),通過this呼叫Context更簡捷。因此他們在某些場合會有些不同。。如下面的例子,使用this會引發錯誤:

Spinner spinner = (Spinner) findViewById(R.id.spinner);
spinner.setAdapter(adapter);            
spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?>arg0, View arg1, int arg2, long arg3){
       Toast.makeText(getBaseContext(),"SELECTED", Toast.LENGTH_SHORT).show(); //這兒使用了getBaseContext()
    }

當把getBaseContext()變成this就會有錯誤。為什麼這種情況下需要使用getBaseContext()方法,而不能使用this呢?

上面說過了this和getBaseContext()指向的物件不同,在這裡this指的不是Activity,而是spinner這個類。因為我們在onItemSelected(AdapterView<?>arg0, View arg1, int arg2, long arg3)方法中使用它。這個方法是來自Spinner類,而Spinner從AdapterView.OnItemSelectedListener介面中繼承這個方法。
getBaseContext()是 ContextWrapper中的方法。雖然這兒可以使用它,但是不建議。因為Toast可以在應用的任何地方使用,並且它不關聯視窗,因此也可以使用Application的上下文。推薦使用XxxClass.this直接指出了使用的是誰的上下文,更簡捷。

Toast要求指出上下文,它是由誰產生的,this返回的就是誰的上下文。再比如點選AlertDialog的按鈕彈出Toast,this返回的是AlertDialog的上下文。

AlertDialog aDialog = new AlertDialog.Builder(this)//這兒使用了this
    .setIcon(R.drawable.ic_launcher)
    .setTitle("Hello World")
    .setPositiveButton("OK", new DialogInterface.OnClickListener() {

    @Override
    public void onClick(DialogInterface arg0, int arg1) {
    Toast.makeText(getBaseContext(), "OK clicked", Toast.LENGTH_SHORT).show();//這兒使用了getBaseContext()
}

關於getApplicationContext()和getApplication()

這一對和上面一對類似,getApplication()只能被Activity和Service裡使用,在Activity類和Service類中定義一樣:

/** 返回屬於這個service(Activity中是activity)的application. */
    public final Application getApplication() {
        return mApplication;
    }

可以看出getApplication()指向的是Application物件,因為Application也是Context 的一個子類,所以getApplication()可以被用來指向Context。
ContextWrapper.getApplicationContext()最終呼叫的是ContextImpl.getApplicationContext():

@Override
    public Context getApplicationContext() {
        return (mPackageInfo != null) ?
                mPackageInfo.getApplication() : mMainThread.getApplication();
    }

他們雖然都可以代表Application的Context,但指向的可能並不是同一個物件(getApplication() != getApplicationContext()),通過getApplication()呼叫Context更簡捷。因此他們在某些場合可能也會有些不同。。比如如果想要獲取在應用清單檔案中宣告的類,最好不要使用getApplicationContext(),並且最好使用強制轉換為自己自定義的Application,因為那樣可能會得不到Application物件。

關於Application的context和Activity的context

在Activity中,this 是其 物件,可以用來指向Activity的context,Activity銷燬Activity的context也被銷燬。Application的上下文,Application銷燬也銷燬。
有時候會有問何時用getApplicationContext()(本人更傾向於使用getApplication())和何時用this的問題,其實就是選擇使用Application的上下文還是Activity的上下文的問題。再說白點就是Application的用法。
通過Application可以來進行一些,如:資料傳遞、資料共享和資料快取等操作,比如我們在某一個Activity中改變了一些全域性變數的值,那麼在同一個應用的其他Activity中如果使用了這些變數值也會隨著改變,這樣就實現了資料傳遞和資料共享。這種涉及到全域性性的操作時,要使用Application的context。可以通過繼承Application類來實現應用程式級的全域性變數,這種全域性變數方法相對靜態類更有保障,直到應用的所有Activity全部被destory掉之後才會被釋放掉。
比如有一個全域性的資料操作類用到了context,這個時候就要getApplication() 而不是用Activity的context,這就保證了資料庫的操作與activity無關(不會一直引用Activity的資源,防止記憶體洩漏),例如在Activity中有:

protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this); 
label.setText("Leaks are bad");
setContentView(label);
}

把activity context傳遞給view,意味著view擁有一個指向activity的引用,進而引用activity佔有的資源。當螢幕旋轉的時候,系統會銷燬當前的activity,儲存狀態資訊,再建立一個新的activity。如果activity資訊比較輕還好,但如果裡面的資訊太多,比如它需要載入一個很大的圖片,當每次旋轉螢幕的時候都銷燬這個圖片,再重新載入會花費不少時間,顯然這是我們不希望的。

實現這個要求的簡單想法就是定義一個靜態的Drawable,這樣Activity類建立銷燬它始終儲存在記憶體中:

public class myactivity extends Activity {
    private static Drawable sBackground;
    protected void onCreate(Bundle state) {
        super.onCreate(state);
        TextView label = new TextView(this);//this在這裡
        label.setText("Leaks are bad");
        if (sBackground == null) {
            sBackground = getDrawable(R.drawable.large_bitmap);
        }
    label.setBackgroundDrawable(sBackground);

    setContentView(label);
    }
}

這段程式看起來很簡單,但是卻問題很大。當螢幕旋轉的時候會有leak(即gc沒法銷燬activity)。我們知道,螢幕旋轉的時候系統會銷燬當前的activity。但是當drawable和view關聯後,drawable儲存了view的reference,即sBackground儲存了label的引用,而label儲存了activity的引用。既然drawable不能銷燬,它所引用和間接引用的都不能銷燬,這樣系統就沒有辦法銷燬當前的activity,於是造成了記憶體洩露。
在Java中記憶體洩漏是指,某個(某些)物件已經不再被使用時應該被gc所回收,但有一個物件持有這個物件的引用因而阻止gc回收這個物件。避免這種記憶體洩露的方法是避免activity中的任何屬於activity的物件的生命週期長過activity,避免由於物件對activity的非正常引用導致activity不能正常被銷燬。這時我們可以使用application的context。application context伴隨application的一生,而與activity的生命週期無關。application context可以通過Context.getApplication()或者Activity.getApplicationContext()方法獲取。但因為我們使用的sBackground不是系統預設的全域性變數,所以我們不能直接像this那樣傳入application 的context。另外我們還有可能在很多處地方使用這種全域性性操作,所以最好自定義一個自己的Application:
首先建立一個MyApplication類,繼承自Application,並作相關實現:

public class MyApplication extends Application{
    private static final Drawable sBackground;
    public void onCreate(){
        super.onCreate();
        setBackground(sBackground);//初始化變數
    }

    public void setBackground(Drawable sBackground)
    {
        this.sBackground = sBackground;
    }

    public String getBackground()
    {
        return sBackground;
    }

}

然後在Manifest.xml檔案中配置自定義的Application

<application
        android:name=".MyApplication">
</application>

這樣就已經實現了一種全域性獲取Context的機制:

public class Myactivity extends Activity {
    private MyApplication app;
    private static Drawable sBackground;
    protected void onCreate(Bundle state) {
        super.onCreate(state);
        app = (MyApplication) getApplication(); // 獲得MyApplication物件
        TextView label = new TextView(this);//在這裡傳入上下文
        label.setText("Leaks are bad");
        if (sBackground == null) {
            sBackground = getDrawable(R.drawable.large_bitmap);//第一次載入背景資源
            app.setBackground(sBackground);//快取到Application中
        }
    label.setBackgroundDrawable(sBackground);

    setContentView(label);
    }
}
注意:這樣當程式啟動的時候會初始化MyApplication類,而不再是預設的Application類。

經常導致記憶體洩漏的一些原因:

1. 一個靜態物件,生命週期長過了所在的Context的生命週期
2. 一個物件,作用域超出了所在Context的作用域

Dialog的使用要求指出Activity的上下文,如果使用Application的Context則無法彈出對話方塊。

Intent也要求指出上下文,如果想啟動一個新的Activity,就必須在Intent中使用Activity的上下文,這樣新啟動的Activity才能和當前Activity有關聯(在activity棧);也可以使用application的context,但是需要在Intent中新增 Intent.FLAG_ACTIVITY_NEW_TASK標誌,當作一個新任務。

Application類原始碼

public class Application extends ContextWrapper implements ComponentCallbacks2 {
    private ArrayList<ComponentCallbacks> mComponentCallbacks =
            new ArrayList<ComponentCallbacks>();
    private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks =
            new ArrayList<ActivityLifecycleCallbacks>();
    private ArrayList<OnProvideAssistDataListener> mAssistCallbacks = null;

    /** @hide */
    public LoadedApk mLoadedApk;
    //Activity生命週期回撥介面
    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);
    }

    /**
     * 使用{@link Application#registerOnProvideAssistDataListener}
     * 和{@link Application#unregisterOnProvideAssistDataListener}的回撥介面 .
     */
    public interface OnProvideAssistDataListener {
        /**
         * 當用戶請求一個 assist的時候呼叫, 
         * 和當前應用的所有的context一塊建立一個完整的{@link Intent#ACTION_ASSIST} Intent。 
         * 你可以覆蓋這個方法去通過bundle存放你喜歡的資料  {@link Intent#EXTRA_ASSIST_CONTEXT} 
         * .
         */
        public void onProvideAssistData(Activity activity, Bundle data);
    }

    public Application() {
        super(null);
    }

    /**當應用啟動時呼叫,
     * 在所有activity, service,
     * or receiver 物件 (包括content providers) 建立之前.
     * 它的實現應該儘可能的不費時間 (比如使用懶載入狀態) 因為這個方法花費的時間直接影響在程序中啟動第一個activity,service, or receiver .
     * 如果重寫這個方法, 一定要呼叫 super.onCreate().
     */
    @CallSuper
    public void onCreate() {
    }

    /**
     * 此方法是用於在模擬的過程環境中。 
     * 它不會在Android裝置產品中被呼叫, where程序被簡單粗暴的killing。
     * 沒有程式碼(包括這個回撥)被執行當這麼做的時候.
     */
    @CallSuper
    public void onTerminate() {
    }

    /**
     * 配置改變時觸發這個方法。
     */
    @CallSuper
    public void onConfigurationChanged(Configuration newConfig) {
        Object[] callbacks = collectComponentCallbacks();
        if (callbacks != null) {
            for (int i=0; i<callbacks.length; i++) {
                ((ComponentCallbacks)callbacks[i]).onConfigurationChanged(newConfig);
            }
        }
    }

    /**
     * 當後臺程式已終止資源還匱乏時會呼叫這個方法。
     * 好的利用程式一般會在這個方法裡面釋放一些沒必要要的資源來應付當後臺程式已終止
     * 前臺利用程式記憶體還不夠時的情況。
     */
    @CallSuper
    public void onLowMemory() {
        Object[] callbacks = collectComponentCallbacks();
        if (callbacks != null) {
            for (int i=0; i<callbacks.length; i++) {
                ((ComponentCallbacks)callbacks[i]).onLowMemory();
            }
        }
    }

    @CallSuper
    public void onTrimMemory(int level) {
        Object[] callbacks = collectComponentCallbacks();
        if (callbacks != null) {
            for (int i=0; i<callbacks.length; i++) {
                Object c = callbacks[i];
                if (c instanceof ComponentCallbacks2) {
                    ((ComponentCallbacks2)c).onTrimMemory(level);
                }
            }
        }
    }
//註冊元件的回撥
    public void registerComponentCallbacks(ComponentCallbacks callback) {
        synchronized (mComponentCallbacks) {
            mComponentCallbacks.add(callback);
        }
    }
//取消註冊元件的回撥
    public void unregisterComponentCallbacks(ComponentCallbacks callback) {
        synchronized (mComponentCallbacks) {
            mComponentCallbacks.remove(callback);
        }
    }

//註冊Activity生命週期的回撥
    public void registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
        synchronized (mActivityLifecycleCallbacks) {
            mActivityLifecycleCallbacks.add(callback);
        }
    }
//取消註冊Activity生命週期的回撥
    public void unregisterActivityLifecycleCallbacks