*本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布
一 背景
在做一个项目时,我们想在应用最早启动时,先做一些判断,然后根据判断的结果再决定要不要对其他应用提供服务。
对其他应用提供服务指的是,我们的应用中有ContentProvider,第三方应用通过call方法调用到我们提供的ContentProvider,ContentProvider执行逻辑后并给调用的返回结果。
当第三方应用调用我们的应用时,我们的应用存在启动和未启动的两种情况。
刚开始,我们将判断逻辑写在了自定义的Application的onCreate方法中,但等到测试时发现了很多意想不到的情况,比如:
逻辑判断之后的结果是不给第三方应用提供“服务”,但有时候第三方应用能够使用服务,而有时候第三方应用不能使等等的问题。
于是我们跟踪代码,发现了
四大组件以及Application的各个方法(attachBaseContext、onCreate、call等)启动顺序,跟我们之前理解的稍稍不一样。
在弄清楚了四大组件和Application
在应用冷启动时的执行顺序后,我们才把遇到的问题彻底解决。
二 验证试验
为了测试四大组件和Application的各种方法
(attachBaseContext、onCreate、call等)被系统调用的顺序
,我们创建一个简单的应用,只包含这5个组件,不考虑一个应用多进程的情况,代码分别为:
MainApplication.java
public class MainApplication extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
Log.v("testLog", getLogStr() );
}
@Override
public void onCreate() {
super.onCreate();
Log.v("testLog", getLogStr());
}
private String getLogStr() {
StackTraceElement[] elements = Thread.currentThread().getStackTrace();
return elements[3].getClassName() + "___" + elements[3].getMethodName();
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.v("testLog", getLogStr());
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
MainService.java
public class MainService extends Service{
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.v("testLog",getLogStr());
return null;
}
@Override
public void onCreate() {
Log.v("testLog",getLogStr());
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v("testLog",getLogStr());
return super.onStartCommand(intent, flags, startId);
}
}
MainReceiver.java
public class MainReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.v("testLog", getLogStr());
}
}
MainProvicer.java
public class MainProvider extends ContentProvider {
@Override
public boolean onCreate() {
Log.v("testLog", getLogStr());
return false;
}
@Nullable
@Override
public Bundle call(String method, String arg, Bundle extras) {
Log.v("testLog", getLogStr());
return super.call(method, arg, extras);
}
... ...
}
AndroidManifest.xml
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:name="com.zxl.test.MainApplication"
android:label="@string/app_name" >
<activity
android:name="com.zxl.test.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="com.zxl.test.MainService"
android:exported="true"/>
<provider
android:name="com.zxl.test.MainProvider"
android:authorities="com.zxl.test.MainProvider"
android:exported="true" />
<receiver android:name="com.zxl.test.MainReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
在以下几个场景测试时,均已冷启动的方式启动应用。
冷启动,指的是在系统没有创建apk这个进程时启动apk。
注意在测试的手机上,不要让测试的应用被禁止关联启动或自启动:
场景一,
点击桌面的图标启动应用,日志如下:
V/testLog (2537) : com.zxl.test.MainApplication___attachBaseContext
V/testLog (2537) : com.zxl.test.MainProvider___onCreate
V/testLog (2537) : com.zxl.test.MainApplication___onCreate
V/testLog (2537) : com.zxl.test.MainActivity___onCreate
场景二,通过 另外一个 应用以启动Service的形式启动应用,
其中 启动MainService的代码如下:
Intent intent = new Intent();
intent.setClassName("com.zxl.test","com.zxl.test.MainService");
intent.setPackage("com.zxl.test");
startService(intent);
日志如下:
V/testLog (2726) : com.zxl.test.MainApplication___attachBaseContext
V/testLog (2726) : com.zxl.test.MainProvider___onCreate
V/testLog (2726) : com.zxl.test.MainApplication___onCreate
V/testLog (2726) : com.zxl.test.MainService___onCreate
V/testLog (2726) : com.zxl.test.MainService___onStartCommand
场景三,应用通过接受开机广播启动的方式启动,日志如下:
V/testLog (1251) : com.zxl.test.MainApplication___attachBaseContext
V/testLog (1251) : com.zxl.test.MainProvider___onCreate
V/testLog (1251) : com.zxl.test.MainApplication___onCreate
V/testLog (1251) : com.zxl.test.MainReceiver___onReceive
场景四,其他应用调用ContentProvider的call方法启动,
其中,调用MainProvider的call代码如下:
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse( "content://com.zxl.test.MainProvider" );
resolver.call( uri,"","",null );
日志如下:
V/testLog (26997) : com.zxl.test.MainApplication___attachBaseContext
V/testLog (26997) : com.zxl.test.MainProvider___onCreate
V/testLog (26997) : com.zxl.test.MainApplication___onCreate
V/testLog (26997) : com.zxl.test.MainProvider___call
结论:
从上面四个场景可以看出:
1. Application的attachBaseContext方法是
优先执行的;
2. ContentProvider的onCreate的方法 比 Application的onCreate的方法
先执行;
3. Activity、Service的onCreate方法以及BroadcastReceiver的onReceive方法,是在MainApplication的onCreate方法之
后执行的;
4. 调用流程为: Application的attachBaseContext ---> ContentProvider的onCreate ----> Application的onCreate ---> Activity、Service等的onCreate(Activity和Service不分先后);
三 问题
问题一:ContentProvider的onCreate一定是优先于Application的onCreate执行的吗?
为了验证这个问题,我们将MainProvider的onCreate的代码改为,MainApplication的代码不变:
public class MainProvider extends ContentProvider {
@Override
public boolean onCreate() {
Log.v("testLog", getLogStr() + " start");
for (int i= 0; i < 10; i++){
SystemClock.sleep(100);
Log.v("testLog", getLogStr() + " i = " + i);
}
Log.v("testLog", getLogStr() + " end");
return false;
}
... ...
}
我们再在上面第四种场景上进行验证,日志如下:
V/testLog (3326) : com.zxl.test.MainApplication___attachBaseContext
V/testLog (3326) : com.zxl.test.MainProvider___onCreate start
V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 0
V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 1
V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 2
V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 3
V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 4
V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 5
V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 6
V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 7
V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 8
V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 9
V/testLog (3326) : com.zxl.test.MainProvider___onCreate end
V/testLog (3326) : com.zxl.test.MainApplication___onCreate
V/testLog (3326) : com.zxl.test.MainActivity___onCreate
问题一结论:
确实是在ContentProvider的onCreate执行完成之后,才会执行Application的onCreate的。
问题二:ContentProvider中的call方法 是在Application的onCreate执行完之后 才执行的吗?
为了验证这个问题,我们将MainProvider和MainApplication的代码改为:
public class MainApplication extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
Log.v("testLog", getLogStr() );
}
@Override
public void onCreate() {
super.onCreate();
Log.v( "testLog", getLogStr() + " start" );
for( int i = 0; i < 10; i++ )
{
Log.v( "testLog", getLogStr() + " i = " + i );
SystemClock.sleep( 50 );
}
Log.v( "testLog", getLogStr() + " end" );
}
}
public class MainProvider extends ContentProvider {
@Override
public boolean onCreate() {
Log.v("testLog", getLogStr());
return false;
}
@Nullable
@Override
public Bundle call(String method, String arg, Bundle extras) {
Log.v("testLog", getLogStr());
for (int i = 0; i < 10; i++) {
Log.v("testLog", getLogStr() + " i = " + i);
SystemClock.sleep(30);
}
return super.call(method, arg, extras);
}
... ...
}
我们还在第四个场景下验证,日志如下:
V/testLog (20660): com.zxl.test.MainApplication___attachBaseContext
V/testLog (20660): com.zxl.test.MainProvider___onCreate
V/testLog (20660): com.zxl.test.MainApplication___onCreate start
V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 0
V/testLog (20660): com.zxl.test.MainProvider___call
V/testLog (20660): com.zxl.test.MainProvider___call i = 0
V/testLog (20660): com.zxl.test.MainProvider___call i = 1
V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 1
V/testLog (20660): com.zxl.test.MainProvider___call i = 2
V/testLog (20660): com.zxl.test.MainProvider___call i = 3
V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 2
V/testLog (20660): com.zxl.test.MainProvider___call i = 4
V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 3
V/testLog (20660): com.zxl.test.MainProvider___call i = 5
V/testLog (20660): com.zxl.test.MainProvider___call i = 6
V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 4
V/testLog (20660): com.zxl.test.MainProvider___call i = 7
V/testLog (20660): com.zxl.test.MainProvider___call i = 8
V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 5
V/testLog (20660): com.zxl.test.MainProvider___call i = 9
V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 6
V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 7
V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 8
V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 9
V/testLog (20660): com.zxl.test.MainApplication___onCreate end
从日志中可以发现,Application的onCreate执行时,ContentProvider的call方法也在同时执行。
问题二结论:
Application的onCreate方法 和 Provider的call方法
不是顺序执行,而是会同时执行。
问题三: 有比Application的attachBaseContext方法更早执行的方法吗?
有,比如:Application所在类的构造方法。
为了验证这个问题,将代码改为:
public class MainApplication extends Application {
public MainApplication(){
Log.v("testLog", "com.zxl.test.MainApplication__MainApplication" );
}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
Log.v("testLog", getLogStr() );
}
@Override
public void onCreate() {
super.onCreate();
Log.v( "testLog", getLogStr() );
}
}
程序启动后,日志为:
V/testLog (20989): com.zxl.test.MainApplication__MainApplication
V/testLog (20989): com.zxl.test.MainApplication___attachBaseContext
V/testLog (20989): com.zxl.test.MainProvider___onCreate
V/testLog (20989): com.zxl.test.MainApplication___onCreate
问题三结论:
Application的构造方法
早于 Application的attachBaseContext方法 调用。
那么有没有比Application的构造方法还早被调用的方法呢?有,自己可以再想想哦。
四 遇到的坑
好了,我们知道attachBaseContext的方法在“一般情况下是最早执行的“,那么在项目中为了能”尽早“的提前初始化某些模块、功能或者参数,那么我们会把代码 从Application的onCreate方法 提前到 attachBaseContext方法中。嗯,一切感觉起来那么美好,直到你运行程序崩溃时... ...
好吧好吧,那些“坑”终于还是来了。
“坑”一:
在Application的attachBaseContext方法中,使用了getApplicationContext方法。
当我发现在attachBaseContext方法中使用getApplicationContext方法返回null时,内心是崩溃。
所以,如果在attachBaseContext方法中要使用context的话,那么使用this吧,别再使用getApplicationContext()方法了。
下文有分析为什么。
“坑”二:这个其实不算很坑,也不会引起崩溃,但需要注意:
在Application的attachBaseContext方法中,去调用自身的
ContentProvider
,那么这个
ContentProvider
会被初始化两次,也就是说这个ContentProvider会被两次调用到onCreate。
如果你在ContentProvider的onCreate中有一些逻辑,那么一定要检查是否会有影响。
做一下验证,在Application中调用Provider的call方法,并在MainActivity中的onCreate方法中调用Provider的call方法,Application的代码,Provider的代码,Activity的代码分别如下:
public class MainApplication extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
Log.v("testLog", getLogStr() );
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse( "content://com.zxl.test.MainProvider" );
resolver.call( uri,"","",null );
}
@Override
public void onCreate() {
super.onCreate();
Log.v( "testLog", getLogStr() );
}
}
public class MainProvider extends ContentProvider {
@Override
public boolean onCreate() {
Log.v("testLog", getLogStr() + " this = " + this );
return false;
}
@Override
public Bundle call(String method, String arg, Bundle extras) {
Log.v("testLog", getLogStr() + " this = " + this);
return super.call(method, arg, extras);
}
... ...
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.v("testLog", getLogStr());
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse( "content://com.zxl.test.MainProvider" );
resolver.call( uri,"","",null );
}
}
启动应用后,日志如下:
V/testLog (25337): com.zxl.test.MainApplication___attachBaseContext
V/testLog (25337): com.zxl.test.MainProvider___onCreate this = com.zxl.test.MainProvider@38fe7481
V/testLog (25337): com.zxl.test.MainProvider___call this = com.zxl.test.MainProvider@38fe7481
V/testLog (25337): com.zxl.test.MainProvider___onCreate this = com.zxl.test.MainProvider@1f17967
V/testLog (25337): com.zxl.test.MainApplication___onCreate
V/testLog (25337): com.zxl.test.MainActivity___onCreate
V/testLog (25337): com.zxl.test.MainProvider___call this = com.zxl.test.MainProvider@38fe7481
可以看到,MainProvider的onCreate的方法被调用了两次(因为MainProvider的两次onCreate打印出的自身对象不一样),而在MainActivity中调用到call方法执行的类,跟MainApplication在attachBaseContext方法执行的类是同一个。
五 源码分析
好了,现象、问题和“坑”都经历了一遍,那么 为什么 会是这样呢?
我们通过看源码,来跟踪:
1.
Application的attachBaseContext、ContentProvider的onCreate以及Application的onCreate在源码中的调用顺序
。
2. 为什么在Application的attachBaseContext中调用getApplicationContext得到的是null。
先看第一个问题,
我们知道Java进程的入口方法一般都是在main中,而Android为了让应用开发者不需要关心应用的创建,已经帮我们进行封装,其实应用main方法是在ActivityThread.java
中的。
我们查看ActivityThread.java的源码,本文以下的源码都以6.0.1_r10基础。
a. ActivityThread.java 的main方法:
frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
... ...
Looper.prepareMainLooper();
- // 1. 先看此处,此处调用了 attach 方法
- ActivityThread thread = new ActivityThread();
thread.attach(false);
... ...
Looper.loop();
- throw new RuntimeException("Main thread loop unexpectedly exited");
}
b.
ActivityThread.java 的attach方法:
frameworks/base/core/java/android/app/ActivityThread.java
private void attach(boolean system) {
- ... ...
- // 2. 上面注释1中,传递的system值为false,所以跳转到这个if语句中
- if (!system) {
- ... ...
// 3. 得到了AMS(ActivityManagerService)在本地的服务代理
final IActivityManager mgr = ActivityManagerNative.getDefault();
try {
// 4. 通知
AMS 创建Application,其实ASM之后还是会回调到ActivityThread的bindApplication方法,- // 而bindApplication方法,会调用到 handleBindApplication 方法
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
// Ignore
}
... ...
} else {
... ...
}
- ... ...
}
c. ActivityThread.java的 handleBindApplication(AppBindData data)方法:
frameworks/base/core/java/android/app/ActivityThread.java
private void handleBindApplication(AppBindData data) {
mBoundApplication = data;
mConfiguration = new Configuration(data.config);
... ...
try {
// 5. makeApplication方法最终会调用到apk的Application的attachBaseContext方法,
// 这里的info其实是LoaderApk的一个实例
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
- ... ...
}
d. LoaderApk.java的 makeApplication方法
frameworks/base/core/java/android/app/LoadedApk.java
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
if (mApplication != null) {
return mApplication;
}
Application app = null;
... ...
try {
java.lang.ClassLoader cl = getClassLoader();
if (!mPackageName.equals("android")) {
initializeJavaContextClassLoader();
}
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
// 5.1 接着看newApplication的方法实现;
// mInstrumentation是Instrumentation的实例
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
} catch (Exception e) {
if (!mActivityThread.mInstrumentation.onException(app, e)) {
throw new RuntimeException(
"Unable to instantiate application " + appClass
+ ": " + e.toString(), e);
}
}
mActivityThread.mAllApplications.add(app);
- mApplication = app;
... ...
return app;
}
e.
Instrumentation.java的相关方法
frameworks/base/core/java/android/app/Instrumentation.java
// 5.2 这个方法是在5.1中调用的方法
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
// 5.3 这个方法直接调用另一个方法
- return newApplication(cl.loadClass(className), context);
}
static public Application newApplication(Class<?> clazz, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = (Application)clazz.newInstance();
// 5.4 在这里终于看到Application这个类了,接着看attach的方法
app.attach(context);
return app;
}
f. Application.java的attach方法
g.
ActivityThread.java的 handleBindApplication方法:
frameworks/base/core/java/android/app/ActivityThread.java
private void handleBindApplication(AppBindData data) {
mBoundApplication = data;
mConfiguration = new Configuration(data.config);
... ...
try {
// 5. makeApplication方法最终会调用到apk的Application的attachBaseContext方法
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
if (!data.restrictedBackupMode) {
List<ProviderInfo> providers = data.providers;
if (providers != null) {
// 6. installContentProviders就是初始化应用中的ContentProvider组件,
// 最终会调用到ContentProvider的onCreate方法;
// 所以,从注释5 和 注释6 的前后顺序,就可以解释为什么Application的attachBaseContext
// 比 ContentProvider的onCreate的方法要早。
installContentProviders(app, providers);
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
}
}
try {
mInstrumentation.onCreate(data.instrumentationArgs);
}
catch (Exception e) {
throw new RuntimeException(
"Exception thrown in onCreate() of "
+ data.instrumentationName + ": " + e.toString(), e);
}
try {
// 7. 这个方法,其实就是调用了Application的onCreate方法,
// 所以,结合注释5、注释6和注释7,可以证实调用顺序确实是:
// Application的attachBaseContext ---> ContentProvider的onCreate ---> Application的onCreate
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
if (!mInstrumentation.onException(app, e)) {
throw new RuntimeException(
"Unable to create application " + app.getClass().getName()
+ ": " + e.toString(), e);
}
}
} finally {
StrictMode.setThreadPolicy(savedPolicy);
}
}
h. 继续跟踪installContentProviders这个方法,而这个方法是会调用到installProvider方法中的,还是在ActivityThread.java中:
frameworks/base/core/java/android/app/ActivityThread.java
private IActivityManager.ContentProviderHolder installProvider(Context context,
IActivityManager.ContentProviderHolder holder, ProviderInfo info,
boolean noisy, boolean noReleaseNeeded, boolean stable) {
... ...
try {
// 6.1.1 通过反射,构造出ContentProvider的实例,
final java.lang.ClassLoader cl = c.getClassLoader();
localProvider = (ContentProvider)cl.
loadClass(info.name).newInstance();
provider = localProvider.getIContentProvider();
if (provider == null) {
Slog.e(TAG, "Failed to instantiate class " +
info.name + " from sourceDir " +
info.applicationInfo.sourceDir);
return null;
}
if (DEBUG_PROVIDER) Slog.v(TAG, "Instantiating local provider " + info.name);
// 6.1.2 此处调用attachInfo,在这个方法中会有一些初始化的动作,最终会调用到ContentProvider的onCreate方法
localProvider.attachInfo(c, info);
} catch (java.lang.Exception e) {
if (!mInstrumentation.onException(null, e)) {
throw new RuntimeException(
"Unable to get provider " + info.name
+ ": " + e.toString(), e);
}
return null;
}
... ...
}
i. 看ContentProvider.java中的attachInfo方法(frameworks/base/core/java/android/content/ContentProvider.java)
frameworks/base/core/java/android/content/ContentProvider.java
private void attachInfo(Context context, ProviderInfo info, boolean testing) {
mNoPerms = testing;
if (mContext == null) {
mContext = context;
if (context != null) {
mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService(
Context.APP_OPS_SERVICE);
}
mMyUid = Process.myUid();
if (info != null) {
setReadPermission(info.readPermission);
setWritePermission(info.writePermission);
setPathPermissions(info.pathPermissions);
mExported = info.exported;
mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0;
setAuthorities(info.authority);
}
// 6.1.3 终于在此处看到调用onCreate方法了
ContentProvider.this.onCreate();
}
}
j. 关于注释7 的mInstrumentation.callApplicationOnCreate(app) 调用到的
Instrumentation.java中的方法
看第二问题,为什么在我们自定义Application中的attachBaseContext方法中,调用getApplicationContext()为null呢?
1. 跟踪 getApplicationContext() 发现是在ContextWrapper.java中实现的:
- /framework/base/core/android/content/ContextWrapper.java
@Override
public Context getApplicationContext() {
- // a. mBase是什么?mBase是Context的一个实例,在这类里面它是通过两种方式被赋值,
- // 第一个是在ContextWrapper的构造方法;第二个是在ContextWrapper的attachBaseContext方法;
- // 而我们是从Application中跟踪过来,而Application的创建过程体现在注释5 到 注释5.5中,
- // 因此,不难发现mBase其实是一个ContextImpl的实例;
return mBase.getApplicationContext();
}
2. 我们看ContextImpl的getApplicationContext方法:
- /framework/base/core/android/app/ContextImpl.java
@Override
public Context getApplicationContext() {
// b. 看逻辑发现,如果mPackageInfo不为空,就调用mPackageInfo的getApplication()方法;
// 而mPackageInfo又是什么呢?
通过看源码发现它是 LoaderApk的实例;- // 这个mPackageInfo是在什么时候得到的呢?接着往下看
return (mPackageInfo != null) ?
mPackageInfo.getApplication() : mMainThread.getApplication();
}
3. mPackageInfo是什么时候赋值的呢?我们从ContextImpl实例化的地方入手,在注释5.1 之前的一行代码看到了 ContextImpl的实例化代码,跟进代码发现,果不其然,看到了mPackageInfo被赋值的地方:
- /framework/base/core/android/app/ContextImpl.java
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
// c. 具体还是调用到了ContextImp的构造方法
return new ContextImpl(null, mainThread,
packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);
}
private ContextImpl(ContextImpl container, ActivityThread mainThread,
LoadedApk packageInfo, IBinder activityToken, UserHandle user, int flags,
Display display, Configuration overrideConfiguration, int createDisplayWithId) {
mOuterContext = this;
... ...
- // c.1 mPackageInfoInfo被赋值了,
- // 而 packageInfo是 从createAppContext中一步步传过来的LoaderApk的实例;
mPackageInfo = packageInfo;
mResourcesManager = ResourcesManager.getInstance();
- ... ...
}
4. 注释b.1所在的流程 早于 注释5.4的(在注释5.4时才调用到了Application的attachBaseContext方法),在我们自定义的Application中attachBaseContext调用getApplicationContext方法时,就到了注释b,而此时mPackageInfo是不为空的,所以会执行mPackageInfo.getApplication(),那么我们再看一下LoadedApk.java中的getApplication方法(正如前面所说,mPackageInfo是LoadedApk的实例),
- /framework/base/core/android/app/LoaderApk.java
// d. 好吧,代码就这么“简单纯朴”;
// 好吧,这不是我们想要的;继续分析mApplication 是什么时候被赋值的
// 在LoaderApk中搜索 “mApplication =”,发现有且仅有一行代码,看接着看注释 d.1
Application getApplication() {
return mApplication;
}
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
if (mApplication != null) {
return mApplication;
}
Application app = null;
... ...
try {
java.lang.ClassLoader cl = getClassLoader();
if (!mPackageName.equals("android")) {
initializeJavaContextClassLoader();
}
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
} catch (Exception e) {
if (!mActivityThread.mInstrumentation.onException(app, e)) {
throw new RuntimeException(
"Unable to instantiate application " + appClass
+ ": " + e.toString(), e);
}
}
mActivityThread.mAllApplications.add(app);
// d.1 此处是仅有的一处 "mApplication =";
// 再看看之前的代码,发现是不是很眼熟,这不就是 之前 注释5.1的那段代码吗?
mApplication = app;
... ...
return app;
}
看到这里找到原因所在了:
因为我们在Application的attachBaseContext方法中调用getApplicationContext()时,mApplication还没有被赋值,所以返回的是空,只有把attachBaseContext方法执行完成后,mApplication才会被赋值。
附图一张:
参看: