Welcome 微信登录

首页 / 操作系统 / Linux / Android应用程序内部启动Activity过程(startActivity)的源代码分析

上文(http://www.linuxidc.com/Linux/2011-08/41835.htm)介绍了Android应用程序的启动过程,即应用程序默认Activity的启动过程,一般来说,这种默认Activity是在新的进程和任务中启动的;本文将继续分析在应用程序内部启动非默认Activity的过程的源代码,这种非默认Activity一般是在原来的进程和任务中启动的。这里,我们像上一篇文章Android应用程序启动过程源代码分析一样,采用再上一篇文章Android应用程序的Activity启动过程简要介绍和学习计划所举的例子来分析在应用程序内部启动非默认Activity的过程。在应用程序内部启动非默认Activity的过程与在应用程序启动器Launcher中启动另外一个应用程序的默认Activity的过程大体上一致的,因此,这里不会像上文Android应用程序启动过程源代码分析一样详细分析每一个步骤,我们着重关注有差别的地方。回忆一下Android应用程序的Activity启动过程简要介绍和学习计划一文所用的应用程序Activity,它包含两个Activity,分别是MainActivity和SubActivity,前者是应用程序的默认Activity,后者是非默认Activity。MainActivity启动起来,通过点击它界面上的按钮,便可以在应用程序内部启动SubActivity。我们先来看一下应用程序的配置文件AndroidManifest.xml,看看这两个Activity是如何配置的:
  1. <?xml version="1.0" encoding="utf-8"?>    
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"    
  3.     package="shy.luo.activity"    
  4.     android:versionCode="1"    
  5.     android:versionName="1.0">    
  6.     <application android:icon="@drawable/icon" android:label="@string/app_name">    
  7.         <activity android:name=".MainActivity"    
  8.                   android:label="@string/app_name">    
  9.             <intent-filter>    
  10.                 <action android:name="android.intent.action.MAIN" />    
  11.                 <category android:name="android.intent.category.LAUNCHER" />    
  12.             </intent-filter>    
  13.         </activity>    
  14.         <activity android:name=".SubActivity"    
  15.                   android:label="@string/sub_activity">    
  16.             <intent-filter>    
  17.                 <action android:name="shy.luo.activity.subactivity"/>    
  18.                 <category android:name="android.intent.category.DEFAULT"/>    
  19.             </intent-filter>    
  20.         </activity>    
  21.     </application>    
  22. </manifest>    
        这里可以很清楚地看到,MainActivity被配置成了应用程序的默认Activity,而SubActivity可以通过名称“shy.luo.activity.subactivity”隐式地启动,我们来看一下src/shy/luo/activity/MainActivity.java文件的内容,可以清楚地看到SubActivity是如何隐式地启动的:
  1. public class MainActivity extends Activity  implements OnClickListener {    
  2.     ......    
  3.     
  4.     @Override    
  5.     public void onClick(View v) {    
  6.         if(v.equals(startButton)) {    
  7.             Intent intent = new Intent("shy.luo.activity.subactivity");    
  8.             startActivity(intent);    
  9.         }    
  10.     }    
  11. }    
       这里,首先创建一个名称为“shy.luo.activity.subactivity”的Intent,然后以这个Intent为参数,通过调用startActivity函数来实现隐式地启动SubActivity。        有了这些背景知识后,我们就来看一下SubActivity启动过程的序列图:  与前面介绍的MainActivity启动过程相比,这里少了中间创建新的进程的步骤;接下来,我们就详细分析一下SubActivity与MainActivity启动过程中有差别的地方,相同的地方请参考Android应用程序启动过程源代码分析一文。Step 1. Activity.startActivity这一步与上一篇文章Android应用程序启动过程源代码分析的Step 2大体一致,通过指定名称“shy.luo.activity.subactivity”来告诉应用程序框架层,它要隐式地启动SubActivity。所不同的是传入的参数intent没有Intent.FLAG_ACTIVITY_NEW_TASK标志,表示这个SubActivity和启动它的MainActivity运行在同一个Task中。Step 2. Activity.startActivityForResult这一步与上一篇文章Android应用程序启动过程源代码分析的Step 3一致。Step 3. Instrumentation.execStartActivity这一步与上一篇文章Android应用程序启动过程源代码分析的Step 4一致。Step 4. ActivityManagerProxy.startActivity这一步与上一篇文章Android应用程序启动过程源代码分析的Step 5一致。Step 5. ActivityManagerService.startActivity这一步与上一篇文章Android应用程序启动过程源代码分析的Step 6一致。Step 6. ActivityStack.startActivityMayWait这一步与上一篇文章Android应用程序启动过程源代码分析的Step 7一致。Step 7. ActivityStack.startActivityLocked这一步与上一篇文章Android应用程序启动过程源代码分析的Step 8一致。Step 8. ActivityStack.startActivityUncheckedLocked这一步与上一篇文章Android应用程序启动过程源代码分析的Step 9有所不同,主要是当前要启动的Activity与启动它的Activity是在同一个Task中运行的,我们来详细看一下。这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中:
  1. public class ActivityStack {  
  2.   
  3.     ......  
  4.   
  5.     final int startActivityUncheckedLocked(ActivityRecord r,  
  6.            ActivityRecord sourceRecord, Uri[] grantedUriPermissions,  
  7.            int grantedMode, boolean onlyIfNeeded, boolean doResume) {  
  8.         final Intent intent = r.intent;  
  9.         final int callingUid = r.launchedFromUid;  
  10.   
  11.         int launchFlags = intent.getFlags();  
  12.   
  13.         ......  
  14.   
  15.         if (sourceRecord == null) {  
  16.            ......  
  17.         } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {  
  18.            ......  
  19.         } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE  
  20.            ......  
  21.         }  
  22.   
  23.         if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {  
  24.            ......  
  25.         }  
  26.   
  27.         boolean addingToTask = false;  
  28.         if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&  
  29.            (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)  
  30.            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK  
  31.            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {  
  32.             ......  
  33.         }  
  34.   
  35.         if (r.packageName != null) {  
  36.            // If the activity being launched is the same as the one currently   
  37.            // at the top, then we need to check if it should only be launched   
  38.            // once.   
  39.            ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);  
  40.            if (top != null && r.resultTo == null) {  
  41.                if (top.realActivity.equals(r.realActivity)) {  
  42.                    ......  
  43.                }  
  44.            }  
  45.   
  46.         } else {  
  47.            ......  
  48.         }  
  49.   
  50.         boolean newTask = false;  
  51.   
  52.         // Should this be considered a new task?   
  53.         if (r.resultTo == null && !addingToTask  
  54.            && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {  
  55.             ......  
  56.   
  57.         } else if (sourceRecord != null) {  
  58.             ......  
  59.             // An existing activity is starting this new activity, so we want   
  60.             // to keep the new one in the same task as the one that is starting   
  61.             // it.   
  62.             r.task = sourceRecord.task;  
  63.             ......  
  64.   
  65.         } else {  
  66.            ......  
  67.         }  
  68.   
  69.         ......  
  70.   
  71.         startActivityLocked(r, newTask, doResume);  
  72.         return START_SUCCESS;  
  73.     }  
  74.   
  75.     ......  
  76.   
  77. }