关于Activity你必须掌握的知识(本篇基于8.0去分析)


@[TOC]

1. Activity启动模式以及使用场景?

  1. standard 标准模式 使用场景: 邮件,默认使用标准模式
  2. singleTop 栈顶复用 :登录页面 ,微信支付 微信回调,推送通知栏等
  3. singleTask 栈内单例模式: 主页面等重复调用的页面
  4. singleInstance 栈内单例模式 系统Launcher, 锁屏页面等,此种模式下系统会为这个模式下的Activity单独开辟一个栈
  5. 总结 singleTop ,singleTask ,singleInstance 三种模式如果应用内存在Activity的实例,就不会重新去创建Activity的实例,而是调用Activity的onNewIntent函数 从而Activity的oncreate和onstart没有被调用
  6. 关于singleInstance 必须知道的故事一: 此时有三个activity,ActivityA,ActivityB,ActivityC,除了ActivityB的启动模式为singleInstance,其他的启动模式都为默认的。在ActivityA里startActivity了一个ActivityB,在ActivityB里startActivity了一个ActivityC。照理来说在当前ActivityC页面按返回键,finish当前界面后应当回到ActivityB界面,但是页面直接回到了ActivityA
  • 分析 singleInstance模式是存在于另一个任务栈中的。也就是说ActivityA和ActivityC是处于同一个任务栈中的,ActivityB则是存在另个栈中。所以当关闭了ActivityC的时候,它自然就会去找当前任务栈存在的activity。当前的activity都关闭了之后,才会去找另一个任务栈中的activity。也就是说当在ActivityC中finish之后,会回到ActivityA的界面,在ActivityA里finish之后会回到ActivityB界面。
  1. 故事二:有两个ActivityA,ActivityB,ActivityA的启动模式为默认的,ActivityB的启动模式为singleInstance。当在ActivityA里startActivity了ActivityB,当前页面为ActivityB。按下home键。应用退到后台。此时再点击图标进入APP,按照天理来说,此时的界面应该是ActivityB,可是奇迹又出现了,当前显示的界面是ActivityA
  • 分析 这是因为当重新启动的时候,系统会先去找主栈(我是这么叫的)里的activity,也就是APP中LAUNCHER的activity所处在的栈。查看是否有存在的activity。没有的话则会重新启动LAUNCHER。
  1. 说了这么多 如果想让Activity回到我们想让它返回的地方如何做呢?
  • 解答在ActivityB定义一个全局变量,public static boolean returnActivityB;界面需要跳转的时候将returnActivityB=true;然后在ActivityA界面onstart方法里判断returnActivityB是否为true,是的话就跳转到ActivityB,同时将returnActivityB=false;这样就能解决跳转的问题了

2. taskAffinity属性

taskAffinity属性和Activity的启动模式息息相关, 这个属性在mainfest中设置,可以理解为taskAffinity为宿主Activity指定了存放的任务栈, taskAffinity只有和singleTask启动模式匹配使用,启动的Activity才会运行在名字和taskAffinity相同的任务栈中

3. onSaveInstanceState()和onRestoreInstanceState()

  • Activity中出现异常关闭时候,尽管实际的Activity已经销毁,但是Android系统会记住它已经存在,系统会创建一个新的实例的Activity使用一组保存的数据来描述Activity在被销毁的状态,这组数据存储在Binder对象的键值对的集合中.

  • onSaveInstanceState 保存你的Activity状态.

     @Override
        protected void onSaveInstanceState(Bundle outState) {
            outState.putString("Activity_State","需要保存的数据");
            // 调用父类交给系统处理,这样系统能保存视图层次结构状态
            super.onSaveInstanceState(outState);
        }
    
  • onRestoreInstanceState()

     @Override
        protected void onRestoreInstanceState(Bundle savedInstanceState) {
            super.onRestoreInstanceState(savedInstanceState);
          //得到异常状态下的实例保存的数据
           String state = savedInstanceState.getString("Activity_State");
            
        }
    
  • 以上二种onSaveInstanceState()和onRestoreInstanceState()触发条件只在Activity异常情况下触发,正常情况下的Activity不会执行以上二个方法,可以自行验证. 具体使用的话如当前页面接受到另外页面传递过来的数据,而且当前页面可能存在奔溃情况, 可以用到这二个方法.

4. onConfigurationChanged()属性屏幕旋转

  • 当系统的配置信息发生改变时,系统才会调用此方法,只有在配置文件AndroidMainfest中处理了configChanges属性,对应的设备配置,该方法才会被调用,

      <activity
                android:configChanges="screenSize|orientation"
                android:name=".MainActivity"
                android:label="@string/app_name">
    
  • 当屏幕方向发生改变时,Activity会被销毁重建,如果在AndroidMainfest中添加处理屏幕方向配置信息,则Activity不会被销毁,而是调用onConfigurationChanged 方法

  • configChanges设置取值

    img
  • 当用户接入一个外接键盘时,默认软键盘会隐藏,系统会自动使用外设键盘,这个过程中Activity的销毁和隐藏执行了二次,并且onConfigurationChanged()方法不会调用,但是在配置文件中设置android:configChanges="keyboardHidden|keyboard"。当接入外设键盘或者拔出外设键盘时,调用的周期是先调用onConfigurationChanged()周期后销毁重建

    1. 分析,为何会二次销毁重建. 一次是键盘的插入当设置android:configChanges="keyboardHidden|keyboard"之后,就不会销毁重建,而是调用onConfigurationChanged()方法。

    2. 但是还有一次销毁重建一直存在. 经过测试发现,接入了外设,除了改变键盘类型的改变,触摸屏也发生改变,

    3. 总结 如果键盘类型发生改变,configChanges属性配置如下的Activity才不会销毁重建,且回调onConfigurationChanged方法:

       <activity
                  android:configChanges="keyboard|keyboardHidden|touchscreen"
                  android:name=".MainActivity"
                  android:label="@string/app_name">
      

5. (主要)Activity 到底是如何启动的

  • 主要分为4个部分来叙述整个Activity是如何启动的
  1. 涉及的名词简介,
  2. Launcher请求AMS过程
    3.AMS到ActivityThread的调用过程,
    4.ActivityThread启动Activity的过程

1. 涉及的类名介绍:

  • ActivityManagerServices 简称AMS 服务端对象,负责整个系统中Activity的生命周期
  • ActivityThread App的入口, 当App开启后,会调用它的main()方法开始运行,main()主要就是开启一个消息循环队列,与AMS配合完成Activity的管理工作, (ActivityThread就是UI线程或者主线程).
  • ApplicationThreadProxy 是ApplicationThread在服务器端的代理对象,负责和客户端的ApplicationThread通讯,但是在android8以后, ApplicationThreadProxyIApplicationThread 取代了,IApplicationThread实际上实现的ApplicationThread
  • instrumentation 每个应用程序只有一个instrumentation 对象每个Activity内部都有一个对改对象的引用,很多时候理解为应用程序进程管家,ActivityThread要创建或者暂停某个Activity时候,都需要instrumentation对象来进行具体操作
  • ActivityStack Activity在AMS的栈管理,用来记录已经启动的Activty的先后关系,状态信息等,通过ActivityStack决定是否需要启动新的进程.
  • ActivityRecord ActivityStack的管理对象,每个Activity在AMS对应的ActivityRecord,来记录Activity的状态以及其他管理信息,其时就是服务端的Activity对象的映像,
  • TaskRecord AMS抽象出来的一个任务概念,记录ActivityRecord的栈,一个Task包含若干个ActivityRecord,AMS用TaskRecord确保Activity启动和退出的顺序,

2. Launcher请求AMS的过程

  • 此处省略init进程的创建,Zygote进程, SystemService,Launcher进程的创建.如果想了解的请自行查看资料和源码

  • Launcher是一个Activity, 它的作用就是创建一个桌面程序,存放日常App的入口,

    public final class Launcher extends Activity
            implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,
    View.OnTouchListener {
          ... 
           Object tag = v.getTag();
            if (tag instanceof ShortcutInfo) {
                onClickAppShortcut(v); //点击应用图标
            } else if (tag instanceof com.android.launcher3.FolderInfo) {
                if (v instanceof FolderIcon) {
                    onClickFolderIcon(v); //点击文件夹
                }
            } else if ((FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && v instanceof PageIndicator)||(v == mAllAppsButton && mAllAppsButton != null)) {
                onClickAllAppsButton(v);
            } else if (tag instanceof AppInfo) {
                startAppShortcutOrInfoActivity(v); //启动应用程序的入口
            } else if (tag instanceof com.android.launcher3.LauncherAppWidgetInfo) {
                if (v instanceof com.android.launcher3.PendingAppWidgetHostView) {
                  //小部件
                    onClickPendingWidget((com.android.launcher3.PendingAppWidgetHostView) v);
                }
            }
        ...
           private void startAppShortcutOrInfoActivity(View v) {
            com.android.launcher3.ItemInfo item = (com.android.launcher3.ItemInfo) v.getTag();
            Intent intent = item.getIntent();
            if (intent == null) {
                throw new IllegalArgumentException("Input must have a valid intent");
            }
          //开始启动Activity了. 发现startActivitySafely()其实当我们点击桌面任意图标的时候都会触发这个方法
            boolean success = startActivitySafely(v, intent, item); //判断启动Activity是否成功
            getUserEventDispatcher().logAppLaunch(v, intent); // TODO for discovered apps b/35802115
    
            if (success && v instanceof BubbleTextView) {
                mWaitingForResume = (BubbleTextView) v;
                mWaitingForResume.setStayPressed(true);
            }
        }
          ...
    }
    

    我们继续跟踪startActivitySafely()方法,

    public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
          ...
            //根Activity会在新的任务栈中启动,标志启动一个新的activity
             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
            try {
                if (Utilities.ATLEAST_MARSHMALLOW
                        && (item instanceof ShortcutInfo)
                        && (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
                        || item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
                        && !((ShortcutInfo) item).isPromise()) {
                     //检查快捷方式 里面也会调用startActivity()方法
                    startShortcutIntentSafely(intent, optsBundle, item);
                } else if (user == null || user.equals(Process.myUserHandle())) {
                    //启动Activity.startActivity()方法
                    startActivity(intent, optsBundle);
                } 
              ....
        }
    

    回到Activity中查看startActivity方法

     @Override
        public void startActivity(Intent intent, @Nullable Bundle options) {
            if (options != null) {
                startActivityForResult(intent, -1, options);
            } else {
                // Note we want to go through this call for compatibility with
                // applications that may have overridden the method.
                startActivityForResult(intent, -1);
            }
        }
    

    startActivityForResult中可以看到调用了Instrumentation.execStartActivity()方法 并且得到一个Instrumentation的对象

    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
                                       @Nullable Bundle options) {
        if (mParent == null) {//mParent表示根Activity 即Launcher
            options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar =
                    mInstrumentation.execStartActivity(//监控应用程序和系统交互
                            this, mMainThread.getApplicationThread(), mToken, this,
                            intent, requestCode, opions);
    

    Instrumentation.execStartActivity方法的具体实现

    public ActivityResult execStartActivity(
                Context who, IBinder contextThread, IBinder token, Activity target,
                Intent intent, int requestCode, Bundle options) {
                  ...
            IApplicationThread whoThread = (IApplicationThread) contextThread;
                              try {
                String[] resolvedTypes = new String[intents.length];
                for (int i=0; i<intents.length; i++) {
                    intents[i].migrateExtraStreamToClipData();
                    intents[i].prepareToLeaveProcess(who);
                    resolvedTypes[i] =intents[i].resolveTypeIfNeeded
                      (who.getContentResolver());
                }
                    // 通过Aidl的方式得到AMS在本地的代理类IActivityManager,通知AMS执行startActivities方法;
                int result = ActivityManager.getService()
                    .startActivities(whoThread, who.getBasePackageName(), intents, resolvedTypes,token, options, userId);
                checkStartActivityResult(result, intents[0]);
            } catch (RemoteException e) {
                throw new RuntimeException("Failure from system", e);
            }
                }
    

    ActivityManager.getService()

     public static IActivityManager getService() {
            return IActivityManagerSingleton.get();
        }
    
        //单例模式
        private static final Singleton<IActivityManager> IActivityManagerSingleton
                = new Singleton<IActivityManager>() {
                    @Override
                    protected IActivityManager create() {
                        final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);//IBnder的类型的AMS
                         //将IBinder对象转换成IActivityManager
                        //此处用的是binder的AIDL方式得到一个转化后的IActivityManager对象,IActivityManager对象是AMS在本地的代理
                        final IActivityManager am = IActivityManager.Stub.asInterface(b);
                        return am;
                    }
                };
    

    简单总结一下: 以下的流程完成了Launcher请求AMS的过程

    Launcher请求AMS的过程.png

3. AMS到ActivityThread的调用过程

AMS收到startActivity的请求之后,会按照如下的方法链进行调用

 //AMS中Activity的启动入口
    @Override
    public final int startActivity(IApplicationThread caller, String callingPackage,
                                   Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
      
        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
                resultWho, requestCode, startFlags, profilerInfo, bOptions,
                UserHandle.getCallingUserId());
    }

在这里又出现了一个新对象ActivityStackSupervisor,通过这个类可以实现对ActivityStack的部分操作

 @Override
 public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
                                         Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
                                         int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
        //判断调进程用者是否被隔离 如果隔离会有SecurityException异常
        enforceNotIsolatedCaller("startActivity");
        //检查调用者权限 没有权限也会有SecurityException异常
        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                userId, false, ALLOW_FULL_ONLY, "startActivity", null);

        // TODO: Switch to user app stacks here.
        return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, bOptions, false, userId, null, null,
                "startActivityAsUser");
    }

ActivityStarter类中的操作

    final int startActivityMayWait(IApplicationThread caller, int callingUid,...){
      ...
                //这个ActivityStarter主要作用,加载Activity控制类,收集所有的逻辑来决定intent和flags转为               //Activity并且将Activity和Task以及Stack相关联
            final ActivityRecord[] outRecord = new ActivityRecord[1];
            int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
                    aInfo, rInfo, voiceSession, voiceInteractor,
                    resultTo, resultWho, requestCode, callingPid,
                    callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                    options, ignoreTargetSecurity, componentSpecified, outRecord, container,
                    inTask, reason);
      ...
    }

int startActivityLocked(...) {

        if (TextUtils.isEmpty(reason)) { //启动理由reason
            throw new IllegalArgumentException("Need to specify a reason.");
        }
       ...
            //startActivity()
        mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,
                aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
                callingPid, callingUid, callingPackage, realCallingPid, realCallingUid,                                startFlags,options, ignoreTargetSecurity, componentSpecified,                                             mLastStartActivityRecord,container, inTask);
        ...
        return mLastStartActivityResult;
    }
 private int startActivity(...){
   ...
    // 即将要启动的Activity的描述类ActivityRecord (用来记录Activty的所有信息)
       ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
                callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
                resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
                mSupervisor, container, options, sourceRecord);
     ...
        return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
                options, inTask, outActivity);
 }
 private int startActivity(...) {
        int result = START_CANCELED;
        try {
            mService.mWindowManager.deferSurfaceLayout();
            result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, doResume, options, inTask, outActivity);
        }
   ...
        return result;
    }
private int startActivityUnchecked(...) {
...
                mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                        mOptions);
  ...
}

ActivityStackSupervisor # resumeFocusedStackTopActivityLocked

    boolean resumeFocusedStackTopActivityLocked(ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
        if (targetStack != null && isFocusedStack(targetStack)) {
            return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
        }
        //获取要启动的Activity 并且所在栈的栈顶的不是处于停止状态的ActivityRecord
        final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
        if (r == null || r.state != RESUMED) {
            //继续执行ActivityStack # resumeTopActivityUncheckedLocked
            mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
        } else if (r.state == RESUMED) {
            // Kick off any lingering app transitions form the MoveTaskToFront operation.
            mFocusedStack.executeAppTransition(targetOptions);
        }
        return false;
    }

ActivityStack # resumeTopActivityUncheckedLocked

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
        if (mStackSupervisor.inResumeTopActivity) {
            // Don't even start recursing.
            return false;
        }
        boolean result = false;
        try {
            // Protect against recursion.
            mStackSupervisor.inResumeTopActivity = true;
            //继续执行
            result = resumeTopActivityInnerLocked(prev, options);
        } finally {
            mStackSupervisor.inResumeTopActivity = false;
        }
        mStackSupervisor.checkReadyForSleepLocked();

        return result;
    }
 private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
        if (!mService.mBooting && !mService.mBooted) {
            // Not ready yet!
            return false;
        }
   ...
      mStackSupervisor.startSpecificActivityLocked(next, true, true);
     ...
 }

ActivityStackSupervisor # startSpecificActivityLocked

void startSpecificActivityLocked(ActivityRecord r,
                                     boolean andResume, boolean checkConfig) {
        // Is this activity's application already running?
        //获取即将要启动的Activity的所在的应用程序进程
      ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);

        r.getStack().setLaunchTime(r);
        //判断要启动的 Activity 所在的应用程序进程如果已经运行
        if (app != null && app.thread != null) {
            try {
                if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                        || !"android".equals(r.info.packageName)) {
                    // Don't add this if it is a platform component that is marked
                    // to run in multiple processes, because this is actually
                    // part of the framework so doesn't make sense to track as a
                    // separate apk in the process.
                    app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                            mService.mProcessStats);
                }
                //继续执行
                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting activity "
                        + r.intent.getComponent().flattenToShortString(), e);
            }
        }

        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }
final boolean realStartActivityLocked(...){
  ...
     //app.thread 指的IApplicationThread它的实现是 ActivityThread 的内部类 ApplicationThread
     // 段代码指的就是要在目标应用程序进程启动 Activity
     //app指的是传入的要启动的Activity所在的应用程序进程 代码只要目的就是要在目标引用程序启动Activity
     //当前代码运行在AMS所在的基础进程(SystemServer进程)中,通过ApplicationThread来与应用程序进行BInder         通信,所以ApplicationThread就是AMS和应用程序通信的桥梁
     app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                    System.identityHashCode(r), r.info,
                    mergedConfiguration.getGlobalConfiguration(),
                    mergedConfiguration.getOverrideConfiguration(), r.compat,
                    r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                    r.persistentState, results, newIntents, !andResume,
                    mService.isNextTransitionForward(), profilerInfo);
    ...
}

看一下时序图再说 源码来回切换有点乱

AMS调用ActivityThread过程.png

4. ActivityThread启动Activity的过程

​ ActivityThread通过BInder接收到AMS发送过来的启动Activity的启动通知调用ApplicationThread的scheduleLaunchActivity方法 因为AMS启动Activity的时候用的 app.thread.scheduleLaunchActivityapp.thread是调用ProcessRecord.IApplicationThread对象,ApplicationThread继承于IApplicationThread.stub 所以执行ActivityThread#ApplicationThread#scheduleLaunchActivity方法

  private class ApplicationThread extends IApplicationThread.Stub {
    ...
        @Override
      public final void scheduleLaunchActivity(){
      ...
        //得到Binder传递过来的消息封装到ActivityClientRecord对象中发送给H H是一个消息进程管理类
       sendMessage(H.LAUNCH_ACTIVITY, r);
    }
      ...
  }

ActivityThread#H #handleMessage

 public void handleMessage(Message msg) {
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    //将ApplicationThread传递过来的参数转换成ActivityClientRecode对象
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
                    //应用程序进程需要启动Activity时需要将改Activity所属的APK加载进来
                    //而 r.packageInfo返回一个loadedAPk,loadedAPk就是用来描述已加载APK文件的
                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    //继续执行
                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                }
            }
 }
    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {         ....
      //初始化WindowManager
        WindowManagerGlobal.initialize();
        //启动Activity
        Activity a = performLaunchActivity(r, customIntent);

        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            reportSizeConfigurations(r);
            Bundle oldState = r.state;
            //将Activity的状态设置为Resume
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);

            if (!r.activity.mFinished && r.startsNotResumed) {
                //去执行将Activity状态设置为Resume
                performPauseActivityIfNeeded(r, reason);
                if (r.isPreHoneycomb()) {
                    r.state = oldState;
                }
            }
        } else {
           //如果出现错误通知AMS关闭当前Activity
            try {
                ActivityManager.getService()
                        .finishActivity(r.token, Activity.RESULT_CANCELED, null,
                                Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }
    }
 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
   ...
       appContext.setOuterContext(activity);
                //初始化Activity activity.attach方法中会创建Window对象并且与Activity自身关联
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback);
     ...
         //Instrumentation.callActivityOnCreate来启动Activity 继续执行
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
   ....
 }

Instrumentation#callActivityOnCreate

 public void callActivityOnCreate(Activity activity, Bundle icicle,
            PersistableBundle persistentState) {
        prePerformCreate(activity);
        activity.performCreate(icicle, persistentState);
        postPerformCreate(activity);
    }

Activity#performCreate

  final void performCreate(Bundle icicle) {
    //释放启动Activity过程中需要的权限
        restoreHasCurrentPermissionRequest(icicle);
        //调用Activity的onCreate方法 ,根Activity就启动完毕 
        onCreate(icicle);
        mActivityTransitionState.readState(icicle);
        performCreateCommon();
    }

终于一个完成的Activity到此就启动完成了...看一下时序图吧 -眼睛都疼....

ActivityThread启动Activity的过程.png

上面这些调用过程非常复杂,源码中各种条件判断让人眼花缭乱,所以说如果你没记住也没关系,你只要记住这个流程,理解了Android在控制Activity生命周期时是如何操作,以及是通过哪几个关键的类进行操作的就可以了,

总结一下 Activity的启动流程:

​ 用户在Launcher程序里点击应用图标时,会通知AMS启动应用的入口Activity,AMS发现这个应用还未启动,则会通知Zygote进程孵化出应用进程,然后在这个dalvik应用进程里执行ActivityThread的main方法。应用进程接下来通知AMS应用进程已启动,AMS保存应用进程的一个代理对象,这样AMS可以通过这个代理对象控制应用进程,然后AMS通知应用进程创建入口Activity的实例,并执行它的生命周期方法

现在也可以理解:

​ 如果应用的组件(包括所有组件Activity,Service,ContentProvider,Receiver) 被启动,肯定会先启动以应用包名为进程名的进程,这些组件都会运行在应用包名为进程名的进程里,并且是在主线程里。应用进程启动时会先创建Application对象,并执行Application对象的生命周期方法,然后才启动应用的组件。

​ 有一种情况比较特殊,那就是为组件设置了特殊的进程名,也就是说通过android:process设置进程名的情况,此时组件运行在单独的进程内。

  • 记录集
    不要使用 startActivityForResult(intent,RESULT_OK) 特此记录
public void startActivity(Intent intent, @Nullable Bundle options) {
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);
        }
    }
//但是RESULT_OK  = -1;
public static final int RESULT_OK  = -1;
//得出结论 如果用RESULT_OK  作为请求码 你不可能从onActivityResult()里面收到任何回调.
startActivityForResult(intent,RESULT_OK) = startActivity()

本文链接地址

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342