Android - 認識Context

app開發中,咱們須要使用app的資源,好比文字、圖片,Activity、Service或者broadcastReceiver等等。時常也會用到getApplicationContext()來獲取一個Context對象。那麼這個Context究竟是什麼呢?java

咱們一塊兒來認識一下Android中的Context。本文主要內容以下圖。android

Android-認識Context.png

Context類簡介

context含義有語境,上下文,背景,環境等等。 Context是維持Android程序中各組件可以正常工做的一個核心功能類。git

Context是一個抽象類。它是一個 app 全局環境的「接口」,由 Android 系統提供繼承類(例如Activity、Service、Application等)。它能鏈接到應用的資源,也能使用應用級的操做,好比啓動activity,廣播和接收intent。github

應用程序中Context的總數目爲: 總Context個數 = Activity個數 + Service個數 + 1(Application Context)bash

Context的子類

簡單的繼承關係示意

Android-Context-class-Inheritance.png

Context
├── ContextImpl
└── ContextWrapper
    ├── Application
    ├── ContextThemeWrapper
    │   └── Activity
    └── Service
複製代碼

從繼承關係圖中能夠看出,Application類、Service類和Activity類都繼承了Context類。應用程序被啓動後,會爲應用程序建立一個全局的Application對應的Context對象。ContextImpl類是Context的真正實現。ContextWrapper類是封裝類。能夠在不改變ContextImpl的狀況下,爲其增長一些自定義操做。ContextWrapper中的mBase其實是一個ContextImpl對象。而ContextImpl類中的mOuterContext是一個Context對象,指向相對應的Activity或Service或Application。app

ContextImpl

Context 是一個抽象類,子類 ContextImpl 實現了Context的方法;爲Activity和其餘應用組件提供基本的context對象。 ContextImpl.java (frameworks\base\core\java\android\app)ide

/** * Common implementation of Context API, which provides the base * context object for Activity and other application components. */
class ContextImpl extends Context { /*...*/ }
複製代碼

ContextWrapper

Wrapper 有封裝的意思;ContextWrapper是Context的封裝類 。這裏使用了裝飾者模式,構造方法中傳入了一個Context 實例。ContextWrapper持有ContextImpl對象。能夠在不改變ContextImpl的狀況下增長一些操做。post

ContextWrapper.java (frameworks\base\core\java\android\content)spa

/** * 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. */
public class ContextWrapper extends Context {
    Context mBase;

    public ContextWrapper(Context base) {
        mBase = base;
    }
    // ...
}
複製代碼

具體操做中,Application類、Activity和Service類與ContextImpl產生交集。.net

ContextThemeWrapper

容許在封裝的context中修改主題(theme)

ContextThemeWrapper.java (frameworks\base\core\java\android\view)

/** * A ContextWrapper that allows you to modify the theme from what is in the * wrapped context. */
public class ContextThemeWrapper extends ContextWrapper { /* ... */ }
複製代碼

其中提供了關於theme的方法,app開發中 android:theme 與此有關。相同的代碼,相同的調用,使用不一樣的 theme 會有不一樣的效果。

getApplicationContext() 和 getBaseContext()

public class ContextWrapper extends Context {
    Context mBase;
    ......
    @Override
    public Context getApplicationContext() {
        return mBase.getApplicationContext();
    }
    ......
    /** * @return the base context as set by the constructor or setBaseContext */
    public Context getBaseContext() {
        return mBase;// Don't use getBaseContext(), just use the Context you have.
    }
    ......
}
複製代碼
getApplicationContext() = android.app.Application@39d42b0e
getBaseContext() = android.app.ContextImpl@1f48c92f
複製代碼

getApplicationContext() 從application取得context。getBaseContext() 從實現類ContextImpl那得來。

Context子類建立流程

Application的建立流程

咱們把關注點先放在application上,暫時忽略源碼中的其餘信息。

Android-Context-Application-flow.png

流程描述:

LoadedApk先經過classLoaderloadClass(className)獲取application的class,再經過clazz.newInstance()建立Application實例。接着調用app.attach(context)方法完成初始化。 Application的attach方法裏調用了本身的attachBaseContext(context), 把第一步建立的ContextImpl實例賦值給ContextWrappermBase成員變量。 到此Application實例建立就完成了。

Activity的建立 - performLaunchActivity

這裏關注的是Activity的實例化以及以前的一些準備過程。

Android-Context-performLaunchActivity-flow.png

流程簡析:

主要關注ActivityThreadperformLaunchActivity方法。經過ContextImplcreateActivityContext得到一個ContextImpl實例,稱爲appContextInstrumentationnewActivity返回了一個Activity實例。LoadedApk.makeApplication能夠得到當前的application,若是當前沒有則新建一個application。最後經過ContextImpl.setOuterContext和Activity的attach方法,將ContextImpl實例與Activity實例關聯到一塊兒。

使用

自定義Application

新建一個MyApplication類,繼承自Application

import android.app.Application;
import android.content.Context;

public class MyApplication extends Application {
    private static Context context;

    public static Context getMyContext() {
        return context;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        context = getApplicationContext();
    }
}
複製代碼

在Manifest中使用MyApplication;

<application android:name="com.rust.aboutview.MyApplication" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme">
    ......
複製代碼

便可在不一樣的地方調用 getMyContext() 方法

MyApplication.getMyContext()
複製代碼

參考

blog.csdn.net/yanbober/ar…

xujiaojie.github.io/2017/09/18/…

xujiaojie.github.io/2017/09/18/…

juejin.im/post/5c37f4…

相關文章
相關標籤/搜索