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();//不报错
}
}