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

来源:互联网 发布:税收大数据应用 编辑:程序博客网 时间:2024/06/05 03:56



一 背景

    在做一个项目时,我们想在应用最早启动时,先做一些判断,然后根据判断的结果再决定要不要对其他应用提供服务。
    对其他应用提供服务指的是,我们的应用中有ContentProvider,第三方应用通过call方法调用到我们提供的ContentProvider,ContentProvider执行逻辑后并给调用的返回结果。当第三方应用调用我们的应用时,我们的应用存在启动和未启动的两种情况。
    刚开始,我们将判断逻辑写在了自定义的Application的onCreate方法中,但等到测试时发现了很多意想不到的情况,比如:
    逻辑判断之后的结果是不给第三方应用提供“服务”,但有时候第三方应用能够使用服务,而有时候第三方应用不能使等等的问题。
    
    于是我们跟踪代码,发现了四大组件以及Application的各个方法(attachBaseContext、onCreate、call等)启动顺序,跟我们之前理解的稍稍不一样。
    在弄清楚了四大组件和Application在应用冷启动时的执行顺序后,我们才把遇到的问题彻底解决。

二 验证试验
    为了测试四大组件和Application的各种方法(attachBaseContext、onCreate、call等)被系统调用的顺序,我们创建一个简单的应用,只包含这5个组件,不考虑一个应用多进程的情况,代码分别为:
MainApplication.java
  1. public class MainApplication extends Application {
  2. @Override
  3. protected void attachBaseContext(Context base) {
  4. super.attachBaseContext(base);
  5. Log.v("testLog", getLogStr() );
  6. }
  7. @Override
  8. public void onCreate() {
  9. super.onCreate();
  10. Log.v("testLog", getLogStr());
  11. }
  12. private String getLogStr() {
  13. StackTraceElement[] elements = Thread.currentThread().getStackTrace();
  14. return elements[3].getClassName() + "___" + elements[3].getMethodName();
  15. }
  16. }
MainActivity.java
  1. public class MainActivity extends AppCompatActivity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. Log.v("testLog", getLogStr());
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_main);
  7. }
  8. }
MainService.java
  1. public class MainService extends Service{
  2. @Nullable
  3. @Override
  4. public IBinder onBind(Intent intent) {
  5. Log.v("testLog",getLogStr());
  6. return null;
  7. }
  8. @Override
  9. public void onCreate() {
  10. Log.v("testLog",getLogStr());
  11. super.onCreate();
  12. }
  13. @Override
  14. public int onStartCommand(Intent intent, int flags, int startId) {
  15. Log.v("testLog",getLogStr());
  16. return super.onStartCommand(intent, flags, startId);
  17. }
  18. }
MainReceiver.java
  1. public class MainReceiver extends BroadcastReceiver {
  2. @Override
  3. public void onReceive(Context context, Intent intent) {
  4. Log.v("testLog", getLogStr());
  5. }
  6. }
MainProvicer.java
  1. public class MainProvider extends ContentProvider {
  2. @Override
  3. public boolean onCreate() {
  4. Log.v("testLog", getLogStr());
  5. return false;
  6. }
  7. @Nullable
  8. @Override
  9. public Bundle call(String method, String arg, Bundle extras) {
  10. Log.v("testLog", getLogStr());
  11. return super.call(method, arg, extras);
  12. }
  13. ... ...
  14. }
AndroidManifest.xml
  1. <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
  2. <application
  3. android:name="com.zxl.test.MainApplication"
  4. android:label="@string/app_name" >
  5. <activity
  6. android:name="com.zxl.test.MainActivity">
  7. <intent-filter>
  8. <action android:name="android.intent.action.MAIN" />
  9. <category android:name="android.intent.category.LAUNCHER" />
  10. </intent-filter>
  11. </activity>
  12. <service android:name="com.zxl.test.MainService"
  13. android:exported="true"/>
  14. <provider
  15. android:name="com.zxl.test.MainProvider"
  16. android:authorities="com.zxl.test.MainProvider"
  17. android:exported="true" />
  18. <receiver android:name="com.zxl.test.MainReceiver">
  19. <intent-filter>
  20. <action android:name="android.intent.action.BOOT_COMPLETED" />
  21. </intent-filter>
  22. </receiver>
  23. </application>

     在以下几个场景测试时,均已冷启动的方式启动应用。
     冷启动,指的是在系统没有创建apk这个进程时启动apk。
      注意在测试的手机上,不要让测试的应用被禁止关联启动或自启动:

      场景一,点击桌面的图标启动应用,日志如下:
  1. V/testLog (2537) : com.zxl.test.MainApplication___attachBaseContext
  2. V/testLog (2537) : com.zxl.test.MainProvider___onCreate
  3. V/testLog (2537) : com.zxl.test.MainApplication___onCreate
  4. V/testLog (2537) : com.zxl.test.MainActivity___onCreate
    
      场景二,通过 另外一个 应用以启动Service的形式启动应用,
      其中 启动MainService的代码如下:
  1. Intent intent = new Intent();
  2. intent.setClassName("com.zxl.test","com.zxl.test.MainService");
  3. intent.setPackage("com.zxl.test");
  4. startService(intent);
    日志如下:
  1. V/testLog (2726) : com.zxl.test.MainApplication___attachBaseContext
  2. V/testLog (2726) : com.zxl.test.MainProvider___onCreate
  3. V/testLog (2726) : com.zxl.test.MainApplication___onCreate
  4. V/testLog (2726) : com.zxl.test.MainService___onCreate
  5. V/testLog (2726) : com.zxl.test.MainService___onStartCommand

    场景三,应用通过接受开机广播启动的方式启动,日志如下:
  1. V/testLog (1251) : com.zxl.test.MainApplication___attachBaseContext
  2. V/testLog (1251) : com.zxl.test.MainProvider___onCreate
  3. V/testLog (1251) : com.zxl.test.MainApplication___onCreate
  4. V/testLog (1251) : com.zxl.test.MainReceiver___onReceive

    场景四,其他应用调用ContentProvider的call方法启动,
    其中,调用MainProvider的call代码如下:
  1. ContentResolver resolver = getContentResolver();
  2. Uri uri = Uri.parse( "content://com.zxl.test.MainProvider" );
  3. resolver.call( uri,"","",null );
    日志如下:
  1. V/testLog (26997) : com.zxl.test.MainApplication___attachBaseContext
  2. V/testLog (26997) : com.zxl.test.MainProvider___onCreate
  3. V/testLog (26997) : com.zxl.test.MainApplication___onCreate
  4. 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的代码不变:
  1. public class MainProvider extends ContentProvider {
  2. @Override
  3. public boolean onCreate() {
  4. Log.v("testLog", getLogStr() + " start");
  5. for (int i= 0; i < 10; i++){
  6. SystemClock.sleep(100);
  7. Log.v("testLog", getLogStr() + " i = " + i);
  8. }
  9. Log.v("testLog", getLogStr() + " end");
  10. return false;
  11. }
  12. ... ...
  13. }
    我们再在上面第四种场景上进行验证,日志如下:
  1. V/testLog (3326) : com.zxl.test.MainApplication___attachBaseContext
  2. V/testLog (3326) : com.zxl.test.MainProvider___onCreate start
  3. V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 0
  4. V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 1
  5. V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 2
  6. V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 3
  7. V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 4
  8. V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 5
  9. V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 6
  10. V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 7
  11. V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 8
  12. V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 9
  13. V/testLog (3326) : com.zxl.test.MainProvider___onCreate end
  14. V/testLog (3326) : com.zxl.test.MainApplication___onCreate
  15. V/testLog (3326) : com.zxl.test.MainActivity___onCreate
       问题一结论:
        确实是在ContentProvider的onCreate执行完成之后,才会执行Application的onCreate的。

    问题二:ContentProvider中的call方法 是在Application的onCreate执行完之后 才执行的吗?
    为了验证这个问题,我们将MainProvider和MainApplication的代码改为:
  1. public class MainApplication extends Application {
  2. @Override
  3. protected void attachBaseContext(Context base) {
  4. super.attachBaseContext(base);
  5. Log.v("testLog", getLogStr() );
  6. }
  7. @Override
  8. public void onCreate() {
  9. super.onCreate();
  10. Log.v( "testLog", getLogStr() + " start" );
  11. for( int i = 0; i < 10; i++ )
  12. {
  13. Log.v( "testLog", getLogStr() + " i = " + i );
  14. SystemClock.sleep( 50 );
  15. }
  16. Log.v( "testLog", getLogStr() + " end" );
  17. }
  18. }
  1. public class MainProvider extends ContentProvider {
  2. @Override
  3. public boolean onCreate() {
  4. Log.v("testLog", getLogStr());
  5. return false;
  6. }
  7. @Nullable
  8. @Override
  9. public Bundle call(String method, String arg, Bundle extras) {
  10. Log.v("testLog", getLogStr());
  11. for (int i = 0; i < 10; i++) {
  12. Log.v("testLog", getLogStr() + " i = " + i);
  13. SystemClock.sleep(30);
  14. }
  15. return super.call(method, arg, extras);
  16. }
  17. ... ...
  18. }
    我们还在第四个场景下验证,日志如下:
  1. V/testLog (20660): com.zxl.test.MainApplication___attachBaseContext
  2. V/testLog (20660): com.zxl.test.MainProvider___onCreate
  3. V/testLog (20660): com.zxl.test.MainApplication___onCreate start
  4. V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 0
  5. V/testLog (20660): com.zxl.test.MainProvider___call
  6. V/testLog (20660): com.zxl.test.MainProvider___call i = 0
  7. V/testLog (20660): com.zxl.test.MainProvider___call i = 1
  8. V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 1
  9. V/testLog (20660): com.zxl.test.MainProvider___call i = 2
  10. V/testLog (20660): com.zxl.test.MainProvider___call i = 3
  11. V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 2
  12. V/testLog (20660): com.zxl.test.MainProvider___call i = 4
  13. V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 3
  14. V/testLog (20660): com.zxl.test.MainProvider___call i = 5
  15. V/testLog (20660): com.zxl.test.MainProvider___call i = 6
  16. V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 4
  17. V/testLog (20660): com.zxl.test.MainProvider___call i = 7
  18. V/testLog (20660): com.zxl.test.MainProvider___call i = 8
  19. V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 5
  20. V/testLog (20660): com.zxl.test.MainProvider___call i = 9
  21. V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 6
  22. V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 7
  23. V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 8
  24. V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 9
  25. V/testLog (20660): com.zxl.test.MainApplication___onCreate end
  从日志中可以发现,Application的onCreate执行时,ContentProvider的call方法也在同时执行。
    问题二结论:
        Application的onCreate方法 和 Provider的call方法 不是顺序执行,而是会同时执行

问题三:   有比Application的attachBaseContext方法更早执行的方法吗?
   有,比如:Application所在类的构造方法。
   为了验证这个问题,将代码改为:
  1. public class MainApplication extends Application {
  2. public MainApplication(){
  3. Log.v("testLog", "com.zxl.test.MainApplication__MainApplication" );
  4. }
  5. @Override
  6. protected void attachBaseContext(Context base) {
  7. super.attachBaseContext(base);
  8. Log.v("testLog", getLogStr() );
  9. }
  10. @Override
  11. public void onCreate() {
  12. super.onCreate();
  13. Log.v( "testLog", getLogStr() );
  14. }
  15. }
      程序启动后,日志为:
  1. V/testLog (20989): com.zxl.test.MainApplication__MainApplication
  2. V/testLog (20989): com.zxl.test.MainApplication___attachBaseContext
  3. V/testLog (20989): com.zxl.test.MainProvider___onCreate
  4. 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的代码分别如下:
  1. public class MainApplication extends Application {
  2. @Override
  3. protected void attachBaseContext(Context base) {
  4. super.attachBaseContext(base);
  5. Log.v("testLog", getLogStr() );
  6. ContentResolver resolver = getContentResolver();
  7. Uri uri = Uri.parse( "content://com.zxl.test.MainProvider" );
  8. resolver.call( uri,"","",null );
  9. }
  10. @Override
  11. public void onCreate() {
  12. super.onCreate();
  13. Log.v( "testLog", getLogStr() );
  14. }
  15. }

  1. public class MainProvider extends ContentProvider {
  2. @Override
  3. public boolean onCreate() {
  4. Log.v("testLog", getLogStr() + " this = " + this );
  5. return false;
  6. }
  7. @Override
  8. public Bundle call(String method, String arg, Bundle extras) {
  9. Log.v("testLog", getLogStr() + " this = " + this);
  10. return super.call(method, arg, extras);
  11. }
  12. ... ...
  13. }

  1. public class MainActivity extends AppCompatActivity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. Log.v("testLog", getLogStr());
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_main);
  7. ContentResolver resolver = getContentResolver();
  8. Uri uri = Uri.parse( "content://com.zxl.test.MainProvider" );
  9. resolver.call( uri,"","",null );
  10. }
  11. }
    启动应用后,日志如下:
  1. V/testLog (25337): com.zxl.test.MainApplication___attachBaseContext
  2. V/testLog (25337): com.zxl.test.MainProvider___onCreate this = com.zxl.test.MainProvider@38fe7481
  3. V/testLog (25337): com.zxl.test.MainProvider___call this = com.zxl.test.MainProvider@38fe7481
  4. V/testLog (25337): com.zxl.test.MainProvider___onCreate this = com.zxl.test.MainProvider@1f17967
  5. V/testLog (25337): com.zxl.test.MainApplication___onCreate
  6. V/testLog (25337): com.zxl.test.MainActivity___onCreate
  7. 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方法:
  1. frameworks/base/core/java/android/app/ActivityThread.java 
  2. public static void main(String[] args) {
  3. Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
  4.      ... ...
  5. Looper.prepareMainLooper();
  6.     // 1. 先看此处,此处调用了 attach 方法
  7. ActivityThread thread = new ActivityThread();
  8. thread.attach(false);
  9.     ... ...
  10. Looper.loop();
  11. throw new RuntimeException("Main thread loop unexpectedly exited");
  12. }
b. ActivityThread.java 的attach方法:
  1. frameworks/base/core/java/android/app/ActivityThread.java 
  2. private void attach(boolean system) {
  3.  ... ...
  4. // 2. 上面注释1中,传递的system值为false,所以跳转到这个if语句中
  5. if (!system) {
  6.  ... ...
  7. // 3. 得到了AMS(ActivityManagerService)在本地的服务代理
  8. final IActivityManager mgr = ActivityManagerNative.getDefault();
  9. try {
  10. // 4. 通知AMS 创建Application,其实ASM之后还是会回调到ActivityThread的bindApplication方法,
  11. // 而bindApplication方法,会调用到 handleBindApplication 方法
  12. mgr.attachApplication(mAppThread);
  13. } catch (RemoteException ex) {
  14. // Ignore
  15. }
  16. ... ...
  17. } else {
  18. ... ...
  19. }
  20. ... ...
  21. }
c.  ActivityThread.java的 handleBindApplication(AppBindData data)方法:
  1. frameworks/base/core/java/android/app/ActivityThread.java 
  2. private void handleBindApplication(AppBindData data) {
  3. mBoundApplication = data;
  4. mConfiguration = new Configuration(data.config);
  5. ... ...
  6. try {
  7. // 5. makeApplication方法最终会调用到apk的Application的attachBaseContext方法,
  8. // 这里的info其实是LoaderApk的一个实例
  9. Application app = data.info.makeApplication(data.restrictedBackupMode, null);
  10. mInitialApplication = app;
  11. ... ...
  12. }
d. LoaderApk.java的 makeApplication方法  
  1. frameworks/base/core/java/android/app/LoadedApk.java 
  2. public Application makeApplication(boolean forceDefaultAppClass,
  3. Instrumentation instrumentation) {
  4. if (mApplication != null) {
  5. return mApplication;
  6. }
  7. Application app = null;
  8. ... ...
  9. try {
  10. java.lang.ClassLoader cl = getClassLoader();
  11. if (!mPackageName.equals("android")) {
  12. initializeJavaContextClassLoader();
  13. }
  14. ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
  15. // 5.1 接着看newApplication的方法实现;
  16. // mInstrumentation是Instrumentation的实例
  17. app = mActivityThread.mInstrumentation.newApplication(
  18. cl, appClass, appContext);
  19. appContext.setOuterContext(app);
  20. } catch (Exception e) {
  21. if (!mActivityThread.mInstrumentation.onException(app, e)) {
  22. throw new RuntimeException(
  23. "Unable to instantiate application " + appClass
  24. + ": " + e.toString(), e);
  25. }
  26. }
  27. mActivityThread.mAllApplications.add(app);
  28. mApplication = app;
  29. ... ...
  30. return app;
  31. }
e. Instrumentation.java的相关方法
  1. frameworks/base/core/java/android/app/Instrumentation.java 
  2. // 5.2 这个方法是在5.1中调用的方法
  3. public Application newApplication(ClassLoader cl, String className, Context context)
  4. throws InstantiationException, IllegalAccessException,
  5. ClassNotFoundException {
  6. // 5.3 这个方法直接调用另一个方法
  7. return newApplication(cl.loadClass(className), context);
  8. }
  9. static public Application newApplication(Class<?> clazz, Context context)
  10. throws InstantiationException, IllegalAccessException,
  11. ClassNotFoundException {
  12. Application app = (Application)clazz.newInstance();
  13. // 5.4 在这里终于看到Application这个类了,接着看attach的方法
  14. app.attach(context);
  15. return app;
  16. }
f. Application.java的attach方法
  1. frameworks/base/core/java/android/app/Application.java 
  2. final void attach(Context context) {
  3. // 5.5 在这里终于看到调用attachBaseContext这个方法了。
  4. // 我们重新回到 注释5 的那段代码,接着往下看
  5. attachBaseContext(context);
  6. mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
  7. }
g.  ActivityThread.java的 handleBindApplication方法:
  1. frameworks/base/core/java/android/app/ActivityThread.java 
  2. private void handleBindApplication(AppBindData data) {
  3. mBoundApplication = data;
  4. mConfiguration = new Configuration(data.config);
  5. ... ...
  6. try {
  7. // 5. makeApplication方法最终会调用到apk的Application的attachBaseContext方法
  8. Application app = data.info.makeApplication(data.restrictedBackupMode, null);
  9. mInitialApplication = app;
  10. if (!data.restrictedBackupMode) {
  11. List<ProviderInfo> providers = data.providers;
  12. if (providers != null) {
  13. // 6. installContentProviders就是初始化应用中的ContentProvider组件,
  14. // 最终会调用到ContentProvider的onCreate方法;
  15. // 所以,从注释5 和 注释6 的前后顺序,就可以解释为什么Application的attachBaseContext
  16. // 比 ContentProvider的onCreate的方法要早。
  17. installContentProviders(app, providers);
  18. mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
  19. }
  20. }
  21. try {
  22. mInstrumentation.onCreate(data.instrumentationArgs);
  23. }
  24. catch (Exception e) {
  25. throw new RuntimeException(
  26. "Exception thrown in onCreate() of "
  27. + data.instrumentationName + ": " + e.toString(), e);
  28. }
  29. try {
  30. // 7. 这个方法,其实就是调用了Application的onCreate方法,
  31. // 所以,结合注释5、注释6和注释7,可以证实调用顺序确实是:
  32. // Application的attachBaseContext ---> ContentProvider的onCreate ---> Application的onCreate
  33. mInstrumentation.callApplicationOnCreate(app);
  34. } catch (Exception e) {
  35. if (!mInstrumentation.onException(app, e)) {
  36. throw new RuntimeException(
  37. "Unable to create application " + app.getClass().getName()
  38. + ": " + e.toString(), e);
  39. }
  40. }
  41. } finally {
  42. StrictMode.setThreadPolicy(savedPolicy);
  43. }
  44. }

h. 继续跟踪installContentProviders这个方法,而这个方法是会调用到installProvider方法中的,还是在ActivityThread.java中:
  1. frameworks/base/core/java/android/app/ActivityThread.java 
  2. private IActivityManager.ContentProviderHolder installProvider(Context context,
  3. IActivityManager.ContentProviderHolder holder, ProviderInfo info,
  4. boolean noisy, boolean noReleaseNeeded, boolean stable) {
  5. ... ...
  6. try {
  7. // 6.1.1 通过反射,构造出ContentProvider的实例,
  8. final java.lang.ClassLoader cl = c.getClassLoader();
  9. localProvider = (ContentProvider)cl.
  10. loadClass(info.name).newInstance();
  11. provider = localProvider.getIContentProvider();
  12. if (provider == null) {
  13. Slog.e(TAG, "Failed to instantiate class " +
  14. info.name + " from sourceDir " +
  15. info.applicationInfo.sourceDir);
  16. return null;
  17. }
  18. if (DEBUG_PROVIDER) Slog.v(TAG, "Instantiating local provider " + info.name);
  19. // 6.1.2 此处调用attachInfo,在这个方法中会有一些初始化的动作,最终会调用到ContentProvider的onCreate方法
  20. localProvider.attachInfo(c, info);
  21. } catch (java.lang.Exception e) {
  22. if (!mInstrumentation.onException(null, e)) {
  23. throw new RuntimeException(
  24. "Unable to get provider " + info.name
  25. + ": " + e.toString(), e);
  26. }
  27. return null;
  28. }
  29. ... ...
  30. }

i. 看ContentProvider.java中的attachInfo方法(frameworks/base/core/java/android/content/ContentProvider.java)
  1. frameworks/base/core/java/android/content/ContentProvider.java 
  2. private void attachInfo(Context context, ProviderInfo info, boolean testing) {
  3. mNoPerms = testing;
  4. if (mContext == null) {
  5. mContext = context;
  6. if (context != null) {
  7. mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService(
  8. Context.APP_OPS_SERVICE);
  9. }
  10. mMyUid = Process.myUid();
  11. if (info != null) {
  12. setReadPermission(info.readPermission);
  13. setWritePermission(info.writePermission);
  14. setPathPermissions(info.pathPermissions);
  15. mExported = info.exported;
  16. mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0;
  17. setAuthorities(info.authority);
  18. }
  19. // 6.1.3 终于在此处看到调用onCreate方法了
  20. ContentProvider.this.onCreate();
  21. }
  22. }

j. 关于注释7 的mInstrumentation.callApplicationOnCreate(app) 调用到的Instrumentation.java中的方法
  1. frameworks/base/core/java/android/app/Instrumentation.java 
  2. public void callApplicationOnCreate(Application app) {
  3. // 7.1 就这么简单明了,在这里看到了真正调用Application的onCreate方法的地方
  4. app.onCreate();
  5. }


   看第二问题,为什么在我们自定义Application中的attachBaseContext方法中,调用getApplicationContext()为null呢?
1. 跟踪 getApplicationContext() 发现是在ContextWrapper.java中实现的:
  1. /framework/base/core/android/content/ContextWrapper.java
  2. @Override
  3. public Context getApplicationContext() {
  4. // a. mBase是什么?mBase是Context的一个实例,在这类里面它是通过两种方式被赋值,
  5. // 第一个是在ContextWrapper的构造方法;第二个是在ContextWrapper的attachBaseContext方法;
  6. // 而我们是从Application中跟踪过来,而Application的创建过程体现在注释5 到 注释5.5中,
  7. // 因此,不难发现mBase其实是一个ContextImpl的实例;
  8. return mBase.getApplicationContext();
  9. }
2. 我们看ContextImpl的getApplicationContext方法:
  1. /framework/base/core/android/app/ContextImpl.java
  2. @Override
  3. public Context getApplicationContext() {
  4. // b. 看逻辑发现,如果mPackageInfo不为空,就调用mPackageInfo的getApplication()方法;
  5. // 而mPackageInfo又是什么呢?通过看源码发现它是 LoaderApk的实例;
  6. // 这个mPackageInfo是在什么时候得到的呢?接着往下看
  7. return (mPackageInfo != null) ?
  8. mPackageInfo.getApplication() : mMainThread.getApplication();
  9. }

3. mPackageInfo是什么时候赋值的呢?我们从ContextImpl实例化的地方入手,在注释5.1 之前的一行代码看到了 ContextImpl的实例化代码,跟进代码发现,果不其然,看到了mPackageInfo被赋值的地方:
  1. /framework/base/core/android/app/ContextImpl.java
  2. static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
  3. if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
  4. // c. 具体还是调用到了ContextImp的构造方法
  5. return new ContextImpl(null, mainThread,
  6. packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);
  7. }
  8. private ContextImpl(ContextImpl container, ActivityThread mainThread,
  9. LoadedApk packageInfo, IBinder activityToken, UserHandle user, int flags,
  10. Display display, Configuration overrideConfiguration, int createDisplayWithId) {
  11. mOuterContext = this;
  12. ... ...
  13. // c.1 mPackageInfoInfo被赋值了,
  14. // 而 packageInfo是 从createAppContext中一步步传过来的LoaderApk的实例;
  15. mPackageInfo = packageInfo;
  16. mResourcesManager = ResourcesManager.getInstance();
  17. ... ...
  18. }

4.  注释b.1所在的流程  早于 注释5.4的(在注释5.4时才调用到了Application的attachBaseContext方法),在我们自定义的Application中attachBaseContext调用getApplicationContext方法时,就到了注释b,而此时mPackageInfo是不为空的,所以会执行mPackageInfo.getApplication(),那么我们再看一下LoadedApk.java中的getApplication方法(正如前面所说,mPackageInfo是LoadedApk的实例),
  1. /framework/base/core/android/app/LoaderApk.java
  2. // d. 好吧,代码就这么“简单纯朴”;
  3. // 好吧,这不是我们想要的;继续分析mApplication 是什么时候被赋值的
  4. // 在LoaderApk中搜索 “mApplication =”,发现有且仅有一行代码,看接着看注释 d.1
  5. Application getApplication() {
  6. return mApplication;
  7. }
  1. public Application makeApplication(boolean forceDefaultAppClass,
  2. Instrumentation instrumentation) {
  3. if (mApplication != null) {
  4. return mApplication;
  5. }
  6. Application app = null;
  7. ... ...
  8. try {
  9. java.lang.ClassLoader cl = getClassLoader();
  10. if (!mPackageName.equals("android")) {
  11. initializeJavaContextClassLoader();
  12. }
  13. ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
  14. app = mActivityThread.mInstrumentation.newApplication(
  15. cl, appClass, appContext);
  16. appContext.setOuterContext(app);
  17. } catch (Exception e) {
  18. if (!mActivityThread.mInstrumentation.onException(app, e)) {
  19. throw new RuntimeException(
  20. "Unable to instantiate application " + appClass
  21. + ": " + e.toString(), e);
  22. }
  23. }
  24. mActivityThread.mAllApplications.add(app);
  25. // d.1 此处是仅有的一处 "mApplication =";
  26. // 再看看之前的代码,发现是不是很眼熟,这不就是 之前 注释5.1的那段代码吗?
  27. mApplication = app;
  28. ... ...
  29. return app;
  30. }
     看到这里找到原因所在了:
     因为我们在Application的attachBaseContext方法中调用getApplicationContext()时,mApplication还没有被赋值,所以返回的是空,只有把attachBaseContext方法执行完成后,mApplication才会被赋值。

附图一张:
 

参看:
1. http://androidxref.com
2. http://blog.csdn.net/u011228356/article/details/45102623
3. http://www.wtoutiao.com/p/1f8OfGz.html

一 背景

    在做一个项目时,我们想在应用最早启动时,先做一些判断,然后根据判断的结果再决定要不要对其他应用提供服务。
    对其他应用提供服务指的是,我们的应用中有ContentProvider,第三方应用通过call方法调用到我们提供的ContentProvider,ContentProvider执行逻辑后并给调用的返回结果。当第三方应用调用我们的应用时,我们的应用存在启动和未启动的两种情况。
    刚开始,我们将判断逻辑写在了自定义的Application的onCreate方法中,但等到测试时发现了很多意想不到的情况,比如:
    逻辑判断之后的结果是不给第三方应用提供“服务”,但有时候第三方应用能够使用服务,而有时候第三方应用不能使等等的问题。
    
    于是我们跟踪代码,发现了四大组件以及Application的各个方法(attachBaseContext、onCreate、call等)启动顺序,跟我们之前理解的稍稍不一样。
    在弄清楚了四大组件和Application在应用冷启动时的执行顺序后,我们才把遇到的问题彻底解决。

二 验证试验
    为了测试四大组件和Application的各种方法(attachBaseContext、onCreate、call等)被系统调用的顺序,我们创建一个简单的应用,只包含这5个组件,不考虑一个应用多进程的情况,代码分别为:
MainApplication.java
  1. public class MainApplication extends Application {
  2. @Override
  3. protected void attachBaseContext(Context base) {
  4. super.attachBaseContext(base);
  5. Log.v("testLog", getLogStr() );
  6. }
  7. @Override
  8. public void onCreate() {
  9. super.onCreate();
  10. Log.v("testLog", getLogStr());
  11. }
  12. private String getLogStr() {
  13. StackTraceElement[] elements = Thread.currentThread().getStackTrace();
  14. return elements[3].getClassName() + "___" + elements[3].getMethodName();
  15. }
  16. }
MainActivity.java
  1. public class MainActivity extends AppCompatActivity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. Log.v("testLog", getLogStr());
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_main);
  7. }
  8. }
MainService.java
  1. public class MainService extends Service{
  2. @Nullable
  3. @Override
  4. public IBinder onBind(Intent intent) {
  5. Log.v("testLog",getLogStr());
  6. return null;
  7. }
  8. @Override
  9. public void onCreate() {
  10. Log.v("testLog",getLogStr());
  11. super.onCreate();
  12. }
  13. @Override
  14. public int onStartCommand(Intent intent, int flags, int startId) {
  15. Log.v("testLog",getLogStr());
  16. return super.onStartCommand(intent, flags, startId);
  17. }
  18. }
MainReceiver.java
  1. public class MainReceiver extends BroadcastReceiver {
  2. @Override
  3. public void onReceive(Context context, Intent intent) {
  4. Log.v("testLog", getLogStr());
  5. }
  6. }
MainProvicer.java
  1. public class MainProvider extends ContentProvider {
  2. @Override
  3. public boolean onCreate() {
  4. Log.v("testLog", getLogStr());
  5. return false;
  6. }
  7. @Nullable
  8. @Override
  9. public Bundle call(String method, String arg, Bundle extras) {
  10. Log.v("testLog", getLogStr());
  11. return super.call(method, arg, extras);
  12. }
  13. ... ...
  14. }
AndroidManifest.xml
  1. <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
  2. <application
  3. android:name="com.zxl.test.MainApplication"
  4. android:label="@string/app_name" >
  5. <activity
  6. android:name="com.zxl.test.MainActivity">
  7. <intent-filter>
  8. <action android:name="android.intent.action.MAIN" />
  9. <category android:name="android.intent.category.LAUNCHER" />
  10. </intent-filter>
  11. </activity>
  12. <service android:name="com.zxl.test.MainService"
  13. android:exported="true"/>
  14. <provider
  15. android:name="com.zxl.test.MainProvider"
  16. android:authorities="com.zxl.test.MainProvider"
  17. android:exported="true" />
  18. <receiver android:name="com.zxl.test.MainReceiver">
  19. <intent-filter>
  20. <action android:name="android.intent.action.BOOT_COMPLETED" />
  21. </intent-filter>
  22. </receiver>
  23. </application>

     在以下几个场景测试时,均已冷启动的方式启动应用。
     冷启动,指的是在系统没有创建apk这个进程时启动apk。
      注意在测试的手机上,不要让测试的应用被禁止关联启动或自启动:

      场景一,点击桌面的图标启动应用,日志如下:
  1. V/testLog (2537) : com.zxl.test.MainApplication___attachBaseContext
  2. V/testLog (2537) : com.zxl.test.MainProvider___onCreate
  3. V/testLog (2537) : com.zxl.test.MainApplication___onCreate
  4. V/testLog (2537) : com.zxl.test.MainActivity___onCreate
    
      场景二,通过 另外一个 应用以启动Service的形式启动应用,
      其中 启动MainService的代码如下:
  1. Intent intent = new Intent();
  2. intent.setClassName("com.zxl.test","com.zxl.test.MainService");
  3. intent.setPackage("com.zxl.test");
  4. startService(intent);
    日志如下:
  1. V/testLog (2726) : com.zxl.test.MainApplication___attachBaseContext
  2. V/testLog (2726) : com.zxl.test.MainProvider___onCreate
  3. V/testLog (2726) : com.zxl.test.MainApplication___onCreate
  4. V/testLog (2726) : com.zxl.test.MainService___onCreate
  5. V/testLog (2726) : com.zxl.test.MainService___onStartCommand

    场景三,应用通过接受开机广播启动的方式启动,日志如下:
  1. V/testLog (1251) : com.zxl.test.MainApplication___attachBaseContext
  2. V/testLog (1251) : com.zxl.test.MainProvider___onCreate
  3. V/testLog (1251) : com.zxl.test.MainApplication___onCreate
  4. V/testLog (1251) : com.zxl.test.MainReceiver___onReceive

    场景四,其他应用调用ContentProvider的call方法启动,
    其中,调用MainProvider的call代码如下:
  1. ContentResolver resolver = getContentResolver();
  2. Uri uri = Uri.parse( "content://com.zxl.test.MainProvider" );
  3. resolver.call( uri,"","",null );
    日志如下:
  1. V/testLog (26997) : com.zxl.test.MainApplication___attachBaseContext
  2. V/testLog (26997) : com.zxl.test.MainProvider___onCreate
  3. V/testLog (26997) : com.zxl.test.MainApplication___onCreate
  4. 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的代码不变:
  1. public class MainProvider extends ContentProvider {
  2. @Override
  3. public boolean onCreate() {
  4. Log.v("testLog", getLogStr() + " start");
  5. for (int i= 0; i < 10; i++){
  6. SystemClock.sleep(100);
  7. Log.v("testLog", getLogStr() + " i = " + i);
  8. }
  9. Log.v("testLog", getLogStr() + " end");
  10. return false;
  11. }
  12. ... ...
  13. }
    我们再在上面第四种场景上进行验证,日志如下:
  1. V/testLog (3326) : com.zxl.test.MainApplication___attachBaseContext
  2. V/testLog (3326) : com.zxl.test.MainProvider___onCreate start
  3. V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 0
  4. V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 1
  5. V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 2
  6. V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 3
  7. V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 4
  8. V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 5
  9. V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 6
  10. V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 7
  11. V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 8
  12. V/testLog (3326) : com.zxl.test.MainProvider___onCreate i = 9
  13. V/testLog (3326) : com.zxl.test.MainProvider___onCreate end
  14. V/testLog (3326) : com.zxl.test.MainApplication___onCreate
  15. V/testLog (3326) : com.zxl.test.MainActivity___onCreate
       问题一结论:
        确实是在ContentProvider的onCreate执行完成之后,才会执行Application的onCreate的。

    问题二:ContentProvider中的call方法 是在Application的onCreate执行完之后 才执行的吗?
    为了验证这个问题,我们将MainProvider和MainApplication的代码改为:
  1. public class MainApplication extends Application {
  2. @Override
  3. protected void attachBaseContext(Context base) {
  4. super.attachBaseContext(base);
  5. Log.v("testLog", getLogStr() );
  6. }
  7. @Override
  8. public void onCreate() {
  9. super.onCreate();
  10. Log.v( "testLog", getLogStr() + " start" );
  11. for( int i = 0; i < 10; i++ )
  12. {
  13. Log.v( "testLog", getLogStr() + " i = " + i );
  14. SystemClock.sleep( 50 );
  15. }
  16. Log.v( "testLog", getLogStr() + " end" );
  17. }
  18. }
  1. public class MainProvider extends ContentProvider {
  2. @Override
  3. public boolean onCreate() {
  4. Log.v("testLog", getLogStr());
  5. return false;
  6. }
  7. @Nullable
  8. @Override
  9. public Bundle call(String method, String arg, Bundle extras) {
  10. Log.v("testLog", getLogStr());
  11. for (int i = 0; i < 10; i++) {
  12. Log.v("testLog", getLogStr() + " i = " + i);
  13. SystemClock.sleep(30);
  14. }
  15. return super.call(method, arg, extras);
  16. }
  17. ... ...
  18. }
    我们还在第四个场景下验证,日志如下:
  1. V/testLog (20660): com.zxl.test.MainApplication___attachBaseContext
  2. V/testLog (20660): com.zxl.test.MainProvider___onCreate
  3. V/testLog (20660): com.zxl.test.MainApplication___onCreate start
  4. V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 0
  5. V/testLog (20660): com.zxl.test.MainProvider___call
  6. V/testLog (20660): com.zxl.test.MainProvider___call i = 0
  7. V/testLog (20660): com.zxl.test.MainProvider___call i = 1
  8. V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 1
  9. V/testLog (20660): com.zxl.test.MainProvider___call i = 2
  10. V/testLog (20660): com.zxl.test.MainProvider___call i = 3
  11. V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 2
  12. V/testLog (20660): com.zxl.test.MainProvider___call i = 4
  13. V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 3
  14. V/testLog (20660): com.zxl.test.MainProvider___call i = 5
  15. V/testLog (20660): com.zxl.test.MainProvider___call i = 6
  16. V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 4
  17. V/testLog (20660): com.zxl.test.MainProvider___call i = 7
  18. V/testLog (20660): com.zxl.test.MainProvider___call i = 8
  19. V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 5
  20. V/testLog (20660): com.zxl.test.MainProvider___call i = 9
  21. V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 6
  22. V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 7
  23. V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 8
  24. V/testLog (20660): com.zxl.test.MainApplication___onCreate i = 9
  25. V/testLog (20660): com.zxl.test.MainApplication___onCreate end
  从日志中可以发现,Application的onCreate执行时,ContentProvider的call方法也在同时执行。
    问题二结论:
        Application的onCreate方法 和 Provider的call方法 不是顺序执行,而是会同时执行

问题三:   有比Application的attachBaseContext方法更早执行的方法吗?
   有,比如:Application所在类的构造方法。
   为了验证这个问题,将代码改为:
  1. public class MainApplication extends Application {
  2. public MainApplication(){
  3. Log.v("testLog", "com.zxl.test.MainApplication__MainApplication" );
  4. }
  5. @Override
  6. protected void attachBaseContext(Context base) {
  7. super.attachBaseContext(base);
  8. Log.v("testLog", getLogStr() );
  9. }
  10. @Override
  11. public void onCreate() {
  12. super.onCreate();
  13. Log.v( "testLog", getLogStr() );
  14. }
  15. }
      程序启动后,日志为:
  1. V/testLog (20989): com.zxl.test.MainApplication__MainApplication
  2. V/testLog (20989): com.zxl.test.MainApplication___attachBaseContext
  3. V/testLog (20989): com.zxl.test.MainProvider___onCreate
  4. 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的代码分别如下:
  1. public class MainApplication extends Application {
  2. @Override
  3. protected void attachBaseContext(Context base) {
  4. super.attachBaseContext(base);
  5. Log.v("testLog", getLogStr() );
  6. ContentResolver resolver = getContentResolver();
  7. Uri uri = Uri.parse( "content://com.zxl.test.MainProvider" );
  8. resolver.call( uri,"","",null );
  9. }
  10. @Override
  11. public void onCreate() {
  12. super.onCreate();
  13. Log.v( "testLog", getLogStr() );
  14. }
  15. }

  1. public class MainProvider extends ContentProvider {
  2. @Override
  3. public boolean onCreate() {
  4. Log.v("testLog", getLogStr() + " this = " + this );
  5. return false;
  6. }
  7. @Override
  8. public Bundle call(String method, String arg, Bundle extras) {
  9. Log.v("testLog", getLogStr() + " this = " + this);
  10. return super.call(method, arg, extras);
  11. }
  12. ... ...
  13. }

  1. public class MainActivity extends AppCompatActivity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. Log.v("testLog", getLogStr());
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_main);
  7. ContentResolver resolver = getContentResolver();
  8. Uri uri = Uri.parse( "content://com.zxl.test.MainProvider" );
  9. resolver.call( uri,"","",null );
  10. }
  11. }
    启动应用后,日志如下:
  1. V/testLog (25337): com.zxl.test.MainApplication___attachBaseContext
  2. V/testLog (25337): com.zxl.test.MainProvider___onCreate this = com.zxl.test.MainProvider@38fe7481
  3. V/testLog (25337): com.zxl.test.MainProvider___call this = com.zxl.test.MainProvider@38fe7481
  4. V/testLog (25337): com.zxl.test.MainProvider___onCreate this = com.zxl.test.MainProvider@1f17967
  5. V/testLog (25337): com.zxl.test.MainApplication___onCreate
  6. V/testLog (25337): com.zxl.test.MainActivity___onCreate
  7. 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方法:
  1. frameworks/base/core/java/android/app/ActivityThread.java 
  2. public static void main(String[] args) {
  3. Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
  4.      ... ...
  5. Looper.prepareMainLooper();
  6.     // 1. 先看此处,此处调用了 attach 方法
  7. ActivityThread thread = new ActivityThread();
  8. thread.attach(false);
  9.     ... ...
  10. Looper.loop();
  11. throw new RuntimeException("Main thread loop unexpectedly exited");
  12. }
b. ActivityThread.java 的attach方法:
  1. frameworks/base/core/java/android/app/ActivityThread.java 
  2. private void attach(boolean system) {
  3.  ... ...
  4. // 2. 上面注释1中,传递的system值为false,所以跳转到这个if语句中
  5. if (!system) {
  6.  ... ...
  7. // 3. 得到了AMS(ActivityManagerService)在本地的服务代理
  8. final IActivityManager mgr = ActivityManagerNative.getDefault();
  9. try {
  10. // 4. 通知AMS 创建Application,其实ASM之后还是会回调到ActivityThread的bindApplication方法,
  11. // 而bindApplication方法,会调用到 handleBindApplication 方法
  12. mgr.attachApplication(mAppThread);
  13. } catch (RemoteException ex) {
  14. // Ignore
  15. }
  16. ... ...
  17. } else {
  18. ... ...
  19. }
  20. ... ...
  21. }
c.  ActivityThread.java的 handleBindApplication(AppBindData data)方法:
  1. frameworks/base/core/java/android/app/ActivityThread.java 
  2. private void handleBindApplication(AppBindData data) {
  3. mBoundApplication = data;
  4. mConfiguration = new Configuration(data.config);
  5. ... ...
  6. try {
  7. // 5. makeApplication方法最终会调用到apk的Application的attachBaseContext方法,
  8. // 这里的info其实是LoaderApk的一个实例
  9. Application app = data.info.makeApplication(data.restrictedBackupMode, null);
  10. mInitialApplication = app;
  11. ... ...
  12. }
d. LoaderApk.java的 makeApplication方法  
  1. frameworks/base/core/java/android/app/LoadedApk.java 
  2. public Application makeApplication(boolean forceDefaultAppClass,
  3. Instrumentation instrumentation) {
  4. if (mApplication != null) {
  5. return mApplication;
  6. }
  7. Application app = null;
  8. ... ...
  9. try {
  10. java.lang.ClassLoader cl = getClassLoader();
  11. if (!mPackageName.equals("android")) {
  12. initializeJavaContextClassLoader();
  13. }
  14. ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
  15. // 5.1 接着看newApplication的方法实现;
  16. // mInstrumentation是Instrumentation的实例
  17. app = mActivityThread.mInstrumentation.newApplication(
  18. cl, appClass, appContext);
  19. appContext.setOuterContext(app);
  20. } catch (Exception e) {
  21. if (!mActivityThread.mInstrumentation.onException(app, e)) {
  22. throw new RuntimeException(
  23. "Unable to instantiate application " + appClass
  24. + ": " + e.toString(), e);
  25. }
  26. }
  27. mActivityThread.mAllApplications.add(app);
  28. mApplication = app;
  29. ... ...
  30. return app;
  31. }
e. Instrumentation.java的相关方法
  1. frameworks/base/core/java/android/app/Instrumentation.java 
  2. // 5.2 这个方法是在5.1中调用的方法
  3. public Application newApplication(ClassLoader cl, String className, Context context)
  4. throws InstantiationException, IllegalAccessException,
  5. ClassNotFoundException {
  6. // 5.3 这个方法直接调用另一个方法
  7. return newApplication(cl.loadClass(className), context);
  8. }
  9. static public Application newApplication(Class<?> clazz, Context context)
  10. throws InstantiationException, IllegalAccessException,
  11. ClassNotFoundException {
  12. Application app = (Application)clazz.newInstance();
  13. // 5.4 在这里终于看到Application这个类了,接着看attach的方法
  14. app.attach(context);
  15. return app;
  16. }
f. Application.java的attach方法
  1. frameworks/base/core/java/android/app/Application.java 
  2. final void attach(Context context) {
  3. // 5.5 在这里终于看到调用attachBaseContext这个方法了。
  4. // 我们重新回到 注释5 的那段代码,接着往下看
  5. attachBaseContext(context);
  6. mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
  7. }
g.  ActivityThread.java的 handleBindApplication方法:
  1. frameworks/base/core/java/android/app/ActivityThread.java 
  2. private void handleBindApplication(AppBindData data) {
  3. mBoundApplication = data;
  4. mConfiguration = new Configuration(data.config);
  5. ... ...
  6. try {
  7. // 5. makeApplication方法最终会调用到apk的Application的attachBaseContext方法
  8. Application app = data.info.makeApplication(data.restrictedBackupMode, null);
  9. mInitialApplication = app;
  10. if (!data.restrictedBackupMode) {
  11. List<ProviderInfo> providers = data.providers;
  12. if (providers != null) {
  13. // 6. installContentProviders就是初始化应用中的ContentProvider组件,
  14. // 最终会调用到ContentProvider的onCreate方法;
  15. // 所以,从注释5 和 注释6 的前后顺序,就可以解释为什么Application的attachBaseContext
  16. // 比 ContentProvider的onCreate的方法要早。
  17. installContentProviders(app, providers);
  18. mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
  19. }
  20. }
  21. try {
  22. mInstrumentation.onCreate(data.instrumentationArgs);
  23. }
  24. catch (Exception e) {
  25. throw new RuntimeException(
  26. "Exception thrown in onCreate() of "
  27. + data.instrumentationName + ": " + e.toString(), e);
  28. }
  29. try {
  30. // 7. 这个方法,其实就是调用了Application的onCreate方法,
  31. // 所以,结合注释5、注释6和注释7,可以证实调用顺序确实是:
  32. // Application的attachBaseContext ---> ContentProvider的onCreate ---> Application的onCreate
  33. mInstrumentation.callApplicationOnCreate(app);
  34. } catch (Exception e) {
  35. if (!mInstrumentation.onException(app, e)) {
  36. throw new RuntimeException(
  37. "Unable to create application " + app.getClass().getName()
  38. + ": " + e.toString(), e);
  39. }
  40. }
  41. } finally {
  42. StrictMode.setThreadPolicy(savedPolicy);
  43. }
  44. }

h. 继续跟踪installContentProviders这个方法,而这个方法是会调用到installProvider方法中的,还是在ActivityThread.java中:
  1. frameworks/base/core/java/android/app/ActivityThread.java 
  2. private IActivityManager.ContentProviderHolder installProvider(Context context,
  3. IActivityManager.ContentProviderHolder holder, ProviderInfo info,
  4. boolean noisy, boolean noReleaseNeeded, boolean stable) {
  5. ... ...
  6. try {
  7. // 6.1.1 通过反射,构造出ContentProvider的实例,
  8. final java.lang.ClassLoader cl = c.getClassLoader();
  9. localProvider = (ContentProvider)cl.
  10. loadClass(info.name).newInstance();
  11. provider = localProvider.getIContentProvider();
  12. if (provider == null) {
  13. Slog.e(TAG, "Failed to instantiate class " +
  14. info.name + " from sourceDir " +
  15. info.applicationInfo.sourceDir);
  16. return null;
  17. }
  18. if (DEBUG_PROVIDER) Slog.v(TAG, "Instantiating local provider " + info.name);
  19. // 6.1.2 此处调用attachInfo,在这个方法中会有一些初始化的动作,最终会调用到ContentProvider的onCreate方法
  20. localProvider.attachInfo(c, info);
  21. } catch (java.lang.Exception e) {
  22. if (!mInstrumentation.onException(null, e)) {
  23. throw new RuntimeException(
  24. "Unable to get provider " + info.name
  25. + ": " + e.toString(), e);
  26. }
  27. return null;
  28. }
  29. ... ...
  30. }

i. 看ContentProvider.java中的attachInfo方法(frameworks/base/core/java/android/content/ContentProvider.java)
  1. frameworks/base/core/java/android/content/ContentProvider.java 
  2. private void attachInfo(Context context, ProviderInfo info, boolean testing) {
  3. mNoPerms = testing;
  4. if (mContext == null) {
  5. mContext = context;
  6. if (context != null) {
  7. mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService(
  8. Context.APP_OPS_SERVICE);
  9. }
  10. mMyUid = Process.myUid();
  11. if (info != null) {
  12. setReadPermission(info.readPermission);
  13. setWritePermission(info.writePermission);
  14. setPathPermissions(info.pathPermissions);
  15. mExported = info.exported;
  16. mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0;
  17. setAuthorities(info.authority);
  18. }
  19. // 6.1.3 终于在此处看到调用onCreate方法了
  20. ContentProvider.this.onCreate();
  21. }
  22. }

j. 关于注释7 的mInstrumentation.callApplicationOnCreate(app) 调用到的Instrumentation.java中的方法
  1. frameworks/base/core/java/android/app/Instrumentation.java 
  2. public void callApplicationOnCreate(Application app) {
  3. // 7.1 就这么简单明了,在这里看到了真正调用Application的onCreate方法的地方
  4. app.onCreate();
  5. }


   看第二问题,为什么在我们自定义Application中的attachBaseContext方法中,调用getApplicationContext()为null呢?
1. 跟踪 getApplicationContext() 发现是在ContextWrapper.java中实现的:
  1. /framework/base/core/android/content/ContextWrapper.java
  2. @Override
  3. public Context getApplicationContext() {
  4. // a. mBase是什么?mBase是Context的一个实例,在这类里面它是通过两种方式被赋值,
  5. // 第一个是在ContextWrapper的构造方法;第二个是在ContextWrapper的attachBaseContext方法;
  6. // 而我们是从Application中跟踪过来,而Application的创建过程体现在注释5 到 注释5.5中,
  7. // 因此,不难发现mBase其实是一个ContextImpl的实例;
  8. return mBase.getApplicationContext();
  9. }
2. 我们看ContextImpl的getApplicationContext方法:
  1. /framework/base/core/android/app/ContextImpl.java
  2. @Override
  3. public Context getApplicationContext() {
  4. // b. 看逻辑发现,如果mPackageInfo不为空,就调用mPackageInfo的getApplication()方法;
  5. // 而mPackageInfo又是什么呢?通过看源码发现它是 LoaderApk的实例;
  6. // 这个mPackageInfo是在什么时候得到的呢?接着往下看
  7. return (mPackageInfo != null) ?
  8. mPackageInfo.getApplication() : mMainThread.getApplication();
  9. }

3. mPackageInfo是什么时候赋值的呢?我们从ContextImpl实例化的地方入手,在注释5.1 之前的一行代码看到了 ContextImpl的实例化代码,跟进代码发现,果不其然,看到了mPackageInfo被赋值的地方:
  1. /framework/base/core/android/app/ContextImpl.java
  2. static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
  3. if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
  4. // c. 具体还是调用到了ContextImp的构造方法
  5. return new ContextImpl(null, mainThread,
  6. packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);
  7. }
  8. private ContextImpl(ContextImpl container, ActivityThread mainThread,
  9. LoadedApk packageInfo, IBinder activityToken, UserHandle user, int flags,
  10. Display display, Configuration overrideConfiguration, int createDisplayWithId) {
  11. mOuterContext = this;
  12. ... ...
  13. // c.1 mPackageInfoInfo被赋值了,
  14. // 而 packageInfo是 从createAppContext中一步步传过来的LoaderApk的实例;
  15. mPackageInfo = packageInfo;
  16. mResourcesManager = ResourcesManager.getInstance();
  17. ... ...
  18. }

4.  注释b.1所在的流程  早于 注释5.4的(在注释5.4时才调用到了Application的attachBaseContext方法),在我们自定义的Application中attachBaseContext调用getApplicationContext方法时,就到了注释b,而此时mPackageInfo是不为空的,所以会执行mPackageInfo.getApplication(),那么我们再看一下LoadedApk.java中的getApplication方法(正如前面所说,mPackageInfo是LoadedApk的实例),
  1. /framework/base/core/android/app/LoaderApk.java
  2. // d. 好吧,代码就这么“简单纯朴”;
  3. // 好吧,这不是我们想要的;继续分析mApplication 是什么时候被赋值的
  4. // 在LoaderApk中搜索 “mApplication =”,发现有且仅有一行代码,看接着看注释 d.1
  5. Application getApplication() {
  6. return mApplication;
  7. }
  1. public Application makeApplication(boolean forceDefaultAppClass,
  2. Instrumentation instrumentation) {
  3. if (mApplication != null) {
  4. return mApplication;
  5. }
  6. Application app = null;
  7. ... ...
  8. try {
  9. java.lang.ClassLoader cl = getClassLoader();
  10. if (!mPackageName.equals("android")) {
  11. initializeJavaContextClassLoader();
  12. }
  13. ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
  14. app = mActivityThread.mInstrumentation.newApplication(
  15. cl, appClass, appContext);
  16. appContext.setOuterContext(app);
  17. } catch (Exception e) {
  18. if (!mActivityThread.mInstrumentation.onException(app, e)) {
  19. throw new RuntimeException(
  20. "Unable to instantiate application " + appClass
  21. + ": " + e.toString(), e);
  22. }
  23. }
  24. mActivityThread.mAllApplications.add(app);
  25. // d.1 此处是仅有的一处 "mApplication =";
  26. // 再看看之前的代码,发现是不是很眼熟,这不就是 之前 注释5.1的那段代码吗?
  27. mApplication = app;
  28. ... ...
  29. return app;
  30. }
     看到这里找到原因所在了:
     因为我们在Application的attachBaseContext方法中调用getApplicationContext()时,mApplication还没有被赋值,所以返回的是空,只有把attachBaseContext方法执行完成后,mApplication才会被赋值。

附图一张:
 

参看:
1. http://androidxref.com
2. http://blog.csdn.net/u011228356/article/details/45102623
3. http://www.wtoutiao.com/p/1f8OfGz.html

0 0