Android Context ContextWrapper ContextImpl Activity Service關係
初識Context
對於Android開發者來說,Activity應該是接觸到最早的四大元件之一。Activity可以渲染layout生成控制元件,可以獲取圖片資源、文字資源、動畫資源等等,還可以啟動另一個Activity,啟動一個後臺的Service。每個Activity都有一個Context,通過這個Context我們幾乎可以做任何我們想做的事情。比如通過context.getSystemService(name)我們可以獲取到Android的內部服務,通過LayoutInflater.from(context)可以載入佈局,通過context.getString(resId)可以獲取資源。Context在我們的學習初期,它幾乎是萬能的。
再後來一些,我們知道了Service,Application內部也有一個Context。然後我們知道了Service是後臺的服務,它與Activity的最大的區別就是沒有介面。Application在一個應用程式中只有一個。
直到有一天我們有可能被問到Activity、Service、Application它們都是Context的子類,它們有什麼區別嗎?Dialog建構函式中的Context 可以傳Application的Context嗎?一開始我們是答不上來的。於是我們翻開原始碼開始探究Context的實現原理
Context原始碼解析
Context類圖
Context和Context子類的原始碼
1. Context原始碼
frameworks/base/core/java/android/content/Context.java
public abstract class Context {
public abstract AssetManager getAssets();
public abstract Resources getResources();
public abstract SharedPreferences getSharedPreferences(File file, int mode);
public abstract Context getApplicationContext ();
public abstract void startActivity(Intent intent);
public abstract ComponentName startService(Intent service);
public abstract Intent registerReceiver(BroadcastReceiver receiver,IntentFilter filter);
public final String getString(@StringRes int resId) {
return getResources().getString(resId);
}
public final CharSequence getText(@StringRes int resId) {
return getResources().getText(resId);
}
public final Drawable getDrawable(@DrawableRes int id) {
return getResources().getDrawable(id, getTheme());
}
...省略其他方法
}
在Context.java中,我列舉出了一些大家經常用到的方法,它們基本上都是抽象方法。看來真正實現了這些方法的Context並不是Context類本尊啊。我們沿著類圖的右邊繼續閱讀原始碼。
2. ContextWrapper原始碼
frameworks/base/core/java/android/content/ContextWrapper.java
public class ContextWrapper extends Context {
Context mBase;
public ContextWrapper(Context base) {
mBase = base;
}
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
public Context getBaseContext() {
return mBase;
}
public abstract AssetManager getAssets(){
return mBase.getAssets();
}
...省略其他方法
}
我這裡選取getAssets()方法作為一個代表,其餘的類似方法其實也是一樣,篇幅有限故省略不表。對比下ContextWrapper和Context類。他們的區別有
- ContextWrapper是Context的子類
- ContextWarpper多了一個成員變數Context mBase
- ContextWrapper多了一個建構函式和attachBaseContext(Context base),他們都是給mBase賦值
- Context中定義的抽象方法getAssets()在ContextWrapper中被實現了
ContextWrapper中的方法比如getAssets()、getResource()都是通過呼叫mBase物件的相關方法來實現的。那麼mBase到底是什麼,是Context類的例項嗎?不是!是Activity、Service、Application嗎?不是(因為這些類中,也沒有getAssets的具體實現)!那就只能是左邊的ContextImpl了。接下來我們看看ContextImpl的原始碼,看看是否它就是ContextWrapper的mBase。
3. ContextImpl原始碼
frameworks/base/core/java/android/app/ContextImpl.java
class ContextImpl extends Context{
final ActivityThread mMainThread;
final LoadedApk mPackageInfo;
private final IBinder mActivityToken
private final String mBasePackageName;
private final String mOpPackageName;
private final @NonNull ResourcesManager mResourcesManager;
private final @NonNull Resources mResources;
private Context mOuterContext;
private int mThemeResource = 0;
private Resources.Theme mTheme = null;
private PackageManager mPackageManager;
@Override
public AssetManager getAssets() {
return getResources().getAssets();
}
@Override
public Resources getResources() {
return mResources;
}
@Override
public PackageManager getPackageManager() {
if (mPackageManager != null) {
return mPackageManager;
}
IPackageManager pm = ActivityThread.getPackageManager();
if (pm != null) {
// Doesn't matter if we make more than one instance.
return (mPackageManager = new ApplicationPackageManager(this, pm));
}
return null;
}
@Override
public void startActivity(Intent intent) {
warnIfCallingFromSystemProcess();
startActivity(intent, null);
}
@Override
public void startActivity(Intent intent, Bundle options) {
warnIfCallingFromSystemProcess();
// Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is
// generally not allowed, except if the caller specifies the task id the activity should
// be launched in.
if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0
&& options != null && ActivityOptions.fromBundle(options).getLaunchTaskId() == -1) {
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);
}
}
首先我們來看下我們常用的一些方法getAssets()、getResource()、getPackageManager()、startActivity(Intent intent),它們在ContextImpl類中都有了具體的實現。可以片面的確定ContextWrapper的mBase指向的就是ContextImpl的例項物件!!!注意這裡只是片面的推斷後面還會有更科學、更有理有據、更嚴肅的推斷。大家先記住這個結論就好了,暫時記作不嚴謹的結論吧。後面會用事實證明
接下來我們看下幾個ContextImpl欄位。
- ActivityThread mMainThread這個顧名思義好像是Activity的執行緒啊?其實不是!從原始碼來看它並不繼承於Thread
frameworks/base/core/java/android/app/ActivityThread.java
public final class ActivityThread {
private ContextImpl mSystemContext;
static volatile IPackageManager sPackageManager;
final ApplicationThread mAppThread = new ApplicationThread();
final Looper mLooper = Looper.myLooper();
final H mH = new H();
final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
// List of new activities (via ActivityRecord.nextIdle) that should
// be reported when next we idle.
ActivityClientRecord mNewActivities = null;
// Number of activities that are currently visible on-screen.
int mNumVisibleActivities = 0;
ArrayList<WeakReference<AssistStructure>> mLastAssistStructures = new ArrayList<>();
private int mLastSessionId;
final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();
AppBindData mBoundApplication;
Profiler mProfiler;
int mCurDefaultDisplayDpi;
boolean mDensityCompatMode;
Configuration mConfiguration;
Configuration mCompatConfiguration;
Application mInitialApplication;
final ArrayList<Application> mAllApplications
= new ArrayList<Application>();
}
1. ContextImpl mSystemContext這個是系統應用才會有的。具體幹嘛用的暫時還不知道
2. ApplicationThread mAppThread,mAppThread是用來和ActivityManagerService端的ApplicationThreadProxy通訊的。他是Binder的子類。是IPC通訊的服務端。當ActivityManagerService對Activity做了相應處理的時候,客戶端程式需要通過mAppThread來做相應的處理。比如生成或控制Activity、Service、Application的生命週期
3. Looper mLooper是android應用程式的主looper
4. ArrayMap<IBinder, ActivityClientRecord> mActivities 當前應用程式所有的Activity在客戶端的記錄
5. int mNumVisibleActivities當前可見的Activity數量
6. ArrayMap<IBinder, Service> mServices = new ArrayMap<>()當前應用程式所有的Service在客戶端的記錄
7. H mH = new H(),H extends Handler mH就是一個Handler,mH是和主執行緒的Looper繫結的,換言之就是mH的handleMessage()是在主執行緒執行的。ApplicationThread的方法是在Binder執行緒池中執行的。在Binder執行緒中啟動Activity需要用mH切換到主執行緒中執行。由於啟動Activity不是本文的講解範圍,就不費過多筆墨了。
8. ActivityThread在一個應用程式中只有一個例項。但是如果應用程式開啟了多程序模式,ActivityThread可能會有多份。比如Service指定android:process為:another。
- LoadedApk mPackageInfo這個是用來記錄Apk資訊的。LoadedApk是在ActivityThread的handleBindApplication()方法中被建立
frameworks/base/core/java/android/app/ActivityThread.java
private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
ClassLoader baseLoader, boolean securityViolation, boolean includeCode,
boolean registerPackage) {
final boolean differentUser = (UserHandle.myUserId() != UserHandle.getUserId(aInfo.uid));
synchronized (mResourcesManager) {
WeakReference<LoadedApk> ref;
if (differentUser) {
// Caching not supported across users
ref = null;
} else if (includeCode) {
ref = mPackages.get(aInfo.packageName);
} else {
ref = mResourcePackages.get(aInfo.packageName);
}
LoadedApk packageInfo = ref != null ? ref.get() : null;
if (packageInfo == null || (packageInfo.mResources != null
&& !packageInfo.mResources.getAssets().isUpToDate())) {
if (localLOGV) Slog.v(TAG, (includeCode ? "Loading code package "
: "Loading resource-only package ") + aInfo.packageName
+ " (in " + (mBoundApplication != null
? mBoundApplication.processName : null)
+ ")");
packageInfo =
new LoadedApk(this, aInfo, compatInfo, baseLoader,
securityViolation, includeCode &&
(aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0, registerPackage);
if (mSystemThread && "android".equals(aInfo.packageName)) {
packageInfo.installSystemApplicationInfo(aInfo,
getSystemContext().mPackageInfo.getClassLoader());
}
if (differentUser) {
// Caching not supported across users
} else if (includeCode) {
mPackages.put(aInfo.packageName,
new WeakReference<LoadedApk>(packageInfo));
} else {
mResourcePackages.put(aInfo.packageName,
new WeakReference<LoadedApk>(packageInfo));
}
}
return packageInfo;
}
}
從原始碼中我們可以知道,LoadedApk是儲存在WeakReference中。如果獲取到為null就重新生成LoadedApk
3. IBinder mActivityToken是WindowManager的遠端代理物件
4. Activity、Service、Appplication
前面我們講了ContextWrapper的Context mBase指向的是具體的ContextImpl物件。而Activity、Service、Application也都是ContextWrapper的直接子類或間接子類。mBase是通過attachBaseContext(Context context)來賦值的。
通讀Activity、Service、Application的原始碼。發現attachBaseContext方法會在attach方法中被呼叫
1. Activity原始碼
frameworks/base/core/java/android/app/Activity.java
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback, WindowControllerCallback {
...省略其他
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window) {
attachBaseContext(context);//1
mFragments.attachHost(null /*parent*/);
mWindow = new PhoneWindow(this, window);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
if (info.uiOptions != 0) {
mWindow.setUiOptions(info.uiOptions);
}
mUiThread = Thread.currentThread();
mMainThread = aThread;
mInstrumentation = instr;
mToken = token;
mIdent = ident;
mApplication = application;
mIntent = intent;
mReferrer = referrer;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstances = lastNonConfigurationInstances;
if (voiceInteractor != null) {
if (lastNonConfigurationInstances != null) {
mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
} else {
mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
Looper.myLooper());
}
}
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}
}
註釋1處說明會通過attachBaseContext(context)把真正的context賦值給mBase。那麼順著呼叫Activity的attach方法。發現呼叫者為ActivityThread的handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason)
frameworks/base/core/java/android/app/ActivityThread.java
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
...省略其他
Activity a = performLaunchActivity(r, customIntent);
...省略其他
}
接著看ActivityThread的performLaunchActivity(r,customIntent)方法,由於方法比較長我會在程式碼裡寫註釋講解
frameworks/base/core/java/android/app/ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
ComponentName component = r.intent.getComponent();
if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
}
if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}
Activity activity = null;
try {
//獲取Android程式的ClassLoader mark0
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
//通過反射建立activity.此時Context mBase還沒有被賦值
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
try {
//生成程式全域性的Application物件,如果存在直接返回,如果不存在則生成,
//mark1 接下來講解Application的時候會講到
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (activity != null) {
//建立給Activity使用的ContextImpl
//mark2
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (r.overrideConfig != null) {
config.updateFrom(r.overrideConfig);
}
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
Window window = null;
if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
window = r.mPendingRemoveWindow;
r.mPendingRemoveWindow = null;
r.mPendingRemoveWindowManager = null;
}
//通過activity的attach方法把生成的appContext賦值給Activity
//mark3
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window);
if (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstances = null;
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
activity.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onCreate()");
}
r.activity = activity;
r.stopped = true;
if (!r.activity.mFinished) {
activity.performStart();
r.stopped = false;
}
if (!r.activity.mFinished) {
if (r.isPersistable()) {
if (r.state != null || r.persistentState != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
r.persistentState);
}
} else if (r.state != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
}
}
if (!r.activity.mFinished) {
activity.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnPostCreate(activity, r.state,
r.persistentState);
} else {
mInstrumentation.callActivityOnPostCreate(activity, r.state);
}
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onPostCreate()");
}
}
}
r.paused = true;
//把ActivityClientRecord儲存到ArrayMap中。在handleResumeActivity中通過token獲取mActivities中的ActivityClientRecord
//mark4
mActivities.put(r.token, r);
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to start activity " + component
+ ": " + e.toString(), e);
}
}
return activity;
}
以上程式碼與本文講解Context相關總結如下
1. mark0 通過反射生成Activity
2. mark1 通過反射生成Application
3. mark2 呼叫ActivityThread的createBaseContextForActivity生成ContextImpl
4. mark3 並通過Activity.attach賦值給Activity的mBase。這裡就完美回答了上面關於ContextImpl原始碼處的那個不嚴謹的結論
5. mark4 把ActivityClientRecord記錄到ArrayMap中
mark2處 createBaseContextForActivity原始碼如下
frameworks/base/core/java/android/app/ActivityThread.java
private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
int displayId = Display.DEFAULT_DISPLAY;
try {
displayId = ActivityManagerNative.getDefault().getActivityDisplayId(r.token);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.token, displayId, r.overrideConfig);//1
appContext.setOuterContext(activity);//2
Context baseContext = appContext;
final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
// For debugging purposes, if the activity's package name contains the value of
// the "debug.use-second-display" system property as a substring, then show
// its content on a secondary display if there is one.
String pkgName = SystemProperties.get("debug.second-display.pkg");
if (pkgName != null && !pkgName.isEmpty()
&& r.packageInfo.mPackageName.contains(pkgName)) {
for (int id : dm.getDisplayIds()) {
if (id != Display.DEFAULT_DISPLAY) {
Display display =
dm.getCompatibleDisplay(id, appContext.getDisplayAdjustments(id));
baseContext = appContext.createDisplayContext(display);
break;
}
}
}
return baseContext;
}
//1 處通過ContextImpl createActivityContext生成ContextImpl。對應的還有兩個類似的方法ActivityThread mainThread和createAppContext(ActivityThread mainThread, LoadedApk packageInfo)。後面我把它們放在一起對比。更容易瞭解到差別
//2 處給ContextImpl設定了outerContext。這裡outerContext就是Activity。歸納總結就是Activity的mBase的outerContext就是Activity本身。Service的mBase的outerContext就是Service本身。Application的mBase的outerContext就是Application本身。是不是有點拗口。
2. Application 建立原始碼
Application建立地方有兩處
1.第一處在前面mark1處,通過makeApplication建立Application
//r.packageInfo為 frameworks/base/core/java/android/app/LoadedApk
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
frameworks/base/core/java/android/app/LoadedApk
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
if (mApplication != null) {
return mApplication;
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");
Application app = null;
//如果AndroidManifest中沒有宣告Application用預設的
String appClass = mApplicationInfo.className;
if (forceDefaultAppClass || (appClass == null)) {
appClass = "android.app.Application";
}
try {
java.lang.ClassLoader cl = getClassLoader();
if (!mPackageName.equals("android")) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
"initializeJavaContextClassLoader");
initializeJavaContextClassLoader();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
//mark1 建立Applicaiton的ContextImpl物件
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
//mark2 通過反射生成Applicaiton物件並attach(appContext)
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
//mark3 設定outerContext
appContext.setOuterContext(app);
} catch (Exception e) {
if (!mActivityThread.mInstrumentation.onException(app, e)) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw new RuntimeException(
"Unable to instantiate application " + appClass
+ ": " + e.toString(), e);
}
}
mActivityThread.mAllApplications.add(app);
mApplication = app;
if (instrumentation != null) {
try {
instrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
if (!instrumentation.onException(app, e)) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw new RuntimeException(
"Unable to create application " + app.getClass().getName()
+ ": " + e.toString(), e);
}
}
}
// Rewrite the R 'constants' for all library apks.
SparseArray<String> packageIdentifiers = getAssets(mActivityThread)
.getAssignedPackageIdentifiers();
final int N = packageIdentifiers.size();
for (int i = 0; i < N; i++) {
final int id = packageIdentifiers.keyAt(i);
if (id == 0x01 || id == 0x7f) {
continue;
}
rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
return app;
}
生成Applicaiton總結如下
- mark1 建立Applicaiton的ContextImpl物件
- mark2 通過反射生成Applicaiton物件並attach(appContext)
frameworks/base/core/java/android/app/Instrumentation
static public Application newApplication(Class<?> clazz, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = (Application)clazz.newInstance();
app.attach(context);
return app;
}
2.第二處在ActivityThread的handleBindApplication()中,這裡才是Application第一次被建立的地方
private void handleBindApplication(AppBindData data) {
...省略其他程式碼
//和前面講解的一樣
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
...省略其他程式碼
}
- mark3 設定outerContext
Application原始碼如下
public class Application extends ContextWrapper implements ComponentCallbacks2 {
/* package */ final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
}
3. Service 建立原始碼
- Service部分原始碼如下
public abstract class Service extends ContextWrapper implements ComponentCallbacks2 {
public final void attach(
Context context,
ActivityThread thread, String className, IBinder token,
Application application, Object activityManager) {
attachBaseContext(context);
mThread = thread; // NOTE: unused - remove?
mClassName = className;
mToken = token;
mApplication = application;
mActivityManager = (IActivityManager)activityManager;
mStartCompatibility = getApplicationInfo().targetSdkVersion
< Build.VERSION_CODES.ECLAIR;
}
}
- ActivityThread的handleCreateService()會建立Service
frameworks/base/core/java/android/app/ActivityThread.java
private void handleCreateService(CreateServiceData data) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
//mark1 反射生成Service物件
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to instantiate service " + data.info.name
+ ": " + e.toString(), e);
}
}
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
//mark2 生成ContextImpl 和Application一樣
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
//確保Application已經生成
Application app = packageInfo.makeApplication(false, mInstrumentation);
//mark3 呼叫service的attach方法
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
service.onCreate();
mServices.put(data.token, service);
try {
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to create service " + data.info.name
+ ": " + e.toString(), e);
}
}
}
Service建立總結如下
- 反射生成Service物件
- 生成ContextImpl 和Application一樣
- 呼叫service的attach方法
4. ContextImpl的createActivityContext和createAppContext區別
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
return new ContextImpl(null, mainThread,
packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);
}
// performLaunchActivity
static ContextImpl createActivityContext(ActivityThread mainThread,
LoadedApk packageInfo, IBinder activityToken, int displayId,
Configuration overrideConfiguration) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
return new ContextImpl(null, mainThread, packageInfo, activityToken, null, 0,
null, overrideConfiguration, displayId);
}
對比以上程式碼發現,他們的方法引數的差別在IBinder activityToken。而activityToken其實是與介面相關的。如果用Application或者Service建立Dialog是會報錯的。原因就是沒有activityToken
4. Dialog報錯模擬
public class TestDialogActivity extends Activity{
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
new Dialog(getApplicationContext()).show();//要報錯
new Dialog(this).show();//不報錯
}
}