您的位置:首页 > 移动开发

Android系统中的Application和四大组件一些方法的启动顺序和一些坑

2017-03-26 17:55 483 查看
*本篇文章已授权微信公众号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();
}
}
[/code]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);
}
}
[/code]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);
}
}
[/code]MainReceiver.java
public class MainReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.v("testLog", getLogStr());
}
}
[/code]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);
}
... ...
}
[/code]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>
[/code]在以下几个场景测试时,均已冷启动的方式启动应用。冷启动,指的是在系统没有创建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
[/code]场景二,通过 另外一个 应用以启动Service的形式启动应用,其中 启动MainService的代码如下:
Intent intent = new Intent();
intent.setClassName("com.zxl.test","com.zxl.test.MainService");
intent.setPackage("com.zxl.test");
startService(intent);
[/code]日志如下:
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
[/code]场景三,应用通过接受开机广播启动的方式启动,日志如下:
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
[/code] 场景四,其他应用调用ContentProvider的call方法启动,其中,调用MainProvider的call代码如下:
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse( "content://com.zxl.test.MainProvider" );
resolver.call( uri,"","",null );
[/code]日志如下:
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
[/code]结论:从上面四个场景可以看出: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;
}
... ...
}
[/code]我们再在上面第四种场景上进行验证,日志如下:
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
[/code]问题一结论:确实是在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" );
}
}
[/code]
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);
}
... ...
}
[/code]我们还在第四个场景下验证,日志如下:
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___onCreatei = 0
V/testLog (20660): com.zxl.test.MainProvider___call
V/testLog (20660): com.zxl.test.MainProvider___calli = 0
V/testLog (20660): com.zxl.test.MainProvider___calli = 1
V/testLog (20660): com.zxl.test.MainApplication___onCreatei = 1
V/testLog (20660): com.zxl.test.MainProvider___calli = 2
V/testLog (20660): com.zxl.test.MainProvider___calli = 3
V/testLog (20660): com.zxl.test.MainApplication___onCreatei = 2
V/testLog (20660): com.zxl.test.MainProvider___calli = 4
V/testLog (20660): com.zxl.test.MainApplication___onCreatei = 3
V/testLog (20660): com.zxl.test.MainProvider___calli = 5
V/testLog (20660): com.zxl.test.MainProvider___calli = 6
V/testLog (20660): com.zxl.test.MainApplication___onCreatei = 4
V/testLog (20660): com.zxl.test.MainProvider___calli = 7
V/testLog (20660): com.zxl.test.MainProvider___calli = 8
V/testLog (20660): com.zxl.test.MainApplication___onCreatei = 5
V/testLog (20660): com.zxl.test.MainProvider___calli = 9
V/testLog (20660): com.zxl.test.MainApplication___onCreatei = 6
V/testLog (20660): com.zxl.test.MainApplication___onCreatei = 7
V/testLog (20660): com.zxl.test.MainApplication___onCreatei = 8
V/testLog (20660): com.zxl.test.MainApplication___onCreatei = 9
V/testLog (20660): com.zxl.test.MainApplication___onCreateend
[/code]从日志中可以发现,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() );
}
}
[/code]程序启动后,日志为:
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
[/code]问题三结论: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() );
}
}
[/code]
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);
}
... ...
}
[/code]
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 );
}
}
[/code]启动应用后,日志如下:
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
[/code]可以看到,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");
}
[/code]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 {
 ... ...
}
... ...
}
[/code]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;
... ...
}
[/code]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;
}
[/code]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;
}
[/code]f. Application.java的attach方法
frameworks/base/core/java/android/app/Application.java
final void attach(Context context) {
// 5.5 在这里终于看到调用attachBaseContext这个方法了。// 我们重新回到 注释5 的那段代码,接着往下看
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
[/code]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);
}
}
[/code]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;
}
... ...
}
[/code]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();
}
}
[/code]j. 关于注释7 的mInstrumentation.callApplicationOnCreate(app) 调用到的Instrumentation.java中的方法
frameworks/base/core/java/android/app/Instrumentation.java
public void callApplicationOnCreate(Application app) {
// 7.1 就这么简单明了,在这里看到了真正调用Application的onCreate方法的地方
app.onCreate();
}[/code]看第二问题,为什么在我们自定义Application中的attachBaseContext方法中,调用getApplicationContext()为null呢?1. 跟踪 getApplicationContext() 发现是在ContextWrapper.java中实现的:
/framework/base/core/android/content/ContextWrapper.java[code]@Override
public Context getApplicationContext() {
// a. mBase是什么?mBase是Context的一个实例,在这类里面它是通过两种方式被赋值,// 第一个是在ContextWrapper的构造方法;第二个是在ContextWrapper的attachBaseContext方法;// 而我们是从Application中跟踪过来,而Application的创建过程体现在注释5 到 注释5.5中,// 因此,不难发现mBase其实是一个ContextImpl的实例;
return mBase.getApplicationContext();
}
[/code]2. 我们看ContextImpl的getApplicationContext方法:
/framework/base/core/android/app/ContextImpl.java[code]@Override
public Context getApplicationContext() {
// b. 看逻辑发现,如果mPackageInfo不为空,就调用mPackageInfo的getApplication()方法;
// 而mPackageInfo又是什么呢?
通过看源码发现它是 LoaderApk的实例;// 这个mPackageInfo是在什么时候得到的呢?接着往下看
return (mPackageInfo != null) ?
mPackageInfo.getApplication() : mMainThread.getApplication();
}
[/code]3. mPackageInfo是什么时候赋值的呢?我们从ContextImpl实例化的地方入手,在注释5.1 之前的一行代码看到了 ContextImpl的实例化代码,跟进代码发现,果不其然,看到了mPackageInfo被赋值的地方:
/framework/base/core/android/app/ContextImpl.java[code]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();
... ...
}
[/code]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[code]// d. 好吧,代码就这么“简单纯朴”;
// 好吧,这不是我们想要的;继续分析mApplication 是什么时候被赋值的
// 在LoaderApk中搜索 “mApplication =”,发现有且仅有一行代码,看接着看注释 d.1
Application getApplication() {
 return mApplication;
}
[/code]
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;
}
[/code]看到这里找到原因所在了:因为我们在Application的attachBaseContext方法中调用getApplicationContext()时,mApplication还没有被赋值,所以返回的是空,只有把attachBaseContext方法执行完成后,mApplication才会被赋值。附图一张:参看:1. http://androidxref.com2. http://blog.csdn.net/u011228356/article/details/451026233. http://www.wtoutiao.com/p/1f8OfGz.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息