app開發中,咱們須要使用app的資源,好比文字、圖片,Activity、Service或者broadcastReceiver等等。時常也會用到getApplicationContext()
來獲取一個Context對象。那麼這個Context究竟是什麼呢?java
咱們一塊兒來認識一下Android中的Context。本文主要內容以下圖。android
Context
類簡介context含義有語境,上下文,背景,環境等等。 Context是維持Android程序中各組件可以正常工做的一個核心功能類。git
Context
是一個抽象類。它是一個 app 全局環境的「接口」,由 Android 系統提供繼承類(例如Activity、Service、Application等)。它能鏈接到應用的資源,也能使用應用級的操做,好比啓動activity,廣播和接收intent。github
應用程序中Context的總數目爲: 總Context個數 = Activity個數 + Service個數 + 1(Application Context)bash
Context
的子類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
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 { /*...*/ }
複製代碼
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
容許在封裝的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 會有不一樣的效果。
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那得來。
咱們把關注點先放在application上,暫時忽略源碼中的其餘信息。
流程描述:
LoadedApk
先經過classLoader
的loadClass(className)
獲取application的class
,再經過clazz.newInstance()
建立Application
實例。接着調用app.attach(context)
方法完成初始化。 Application的attach方法裏調用了本身的attachBaseContext(context)
, 把第一步建立的ContextImpl
實例賦值給ContextWrapper
的mBase
成員變量。 到此Application實例建立就完成了。
這裏關注的是Activity的實例化以及以前的一些準備過程。
流程簡析:
主要關注ActivityThread
的performLaunchActivity
方法。經過ContextImpl
的createActivityContext
得到一個ContextImpl實例,稱爲appContext
。Instrumentation
的newActivity
返回了一個Activity實例。LoadedApk.makeApplication
能夠得到當前的application,若是當前沒有則新建一個application。最後經過ContextImpl.setOuterContext
和Activity的attach
方法,將ContextImpl實例與Activity實例關聯到一塊兒。
新建一個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()
複製代碼
xujiaojie.github.io/2017/09/18/…