探索7.x, 全面解析Activity启动框架 (1)

欢迎Follow我的GitHub, 关注我的简书, 博客目录.

Activity的启动框架

本文的合集已经编著成书,高级Android开发强化实战,欢迎各位读友的建议和指导。在京东即可购买:https://item.jd.com/12385680.html

Android

无论怎么说, Activity都是Android最核心的组件, 主要负责向用户展示应用信息. Activity的生命周期由Android系统控制, 启动与绘制都是自动完成. 对于开发人员而言, 仅仅是一句startActivity, 就完成了全部, 但是在平凡的表象下隐藏着惊人的秘密. 让我们拨开迷雾, 一起探索Activity的启动框架! Know more the world, know more ourselves.

Activity

本文源码来源Android SDK 25(即7.1), 逻辑与低版本不同. 在AMS与ASS之间又添加ActivityStarter, 负责管理Activity的启动.

Activity的启动框架图

Activity的启动框架

Activity与Instrumentation

最简单的Activity启动方式, 如下:

Intent intent = new Intent(this, TestActivity.class);
startActivity(intent);

startActivity方法存在于Activity类中, Activity类的调用流程:

  1. Activity#startActivity(Intent)
  2. Activity#startActivityForResult(Intent, int, Bundle)

Activity#startActivityForResult核心是mInstrumentation.execStartActivity

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
        @Nullable Bundle options) {
    if (mParent == null) {
        // ...
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, this,
                intent, requestCode, options); // 核心方法
        // ...
    } else {
        // ...
    }
}

Instrumentation类负责监控系统与应用之间的交互.

execStartActivity核心是ActivityManagerNative类的getDefault#startActivity, 获取IActivityManager单例, 本质是ServiceManager.getService("activity"), 即ActivityManagerService. 通过Binder, 远程调用ActivityManagerService类的startActivity方法.

public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
    // ...
    try {
        // ...
        int result = ActivityManagerNative.getDefault()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target != null ? target.mEmbeddedID : null,
                    requestCode, 0, null, options); // 核心方法
        // ...
    } // ...
    return null;
}

Activity启动通过远程调用, 由当前应用交给ActivityManagerService(AMS)处理.


ActivityManagerService

ActivityManagerService类是负责启动Activity的核心服务, 简称AMS. 启动逻辑包含在ActivityStarter, ActivityStackSupervisor和ActivityStack和三个类中, ActivityStarter负责启动, ActivityStackSupervisor负责管理Stack和TaskRecord, ActivityStack负责管理栈内的Activity.

Stack和TaskRecord示例:

  Stack #1:
    Running activities (most recent first):
      TaskRecord{3caa65e3 #2711 A=me.chunyu.spike.wcl_activity_launchmode_demo U=0 sz=2}
        Run #1: ActivityRecord{36b06e99 u0 me.chunyu.spike.wcl_activity_launchmode_demo/.TestAActivity t2711}
        Run #0: ActivityRecord{27396226 u0 me.chunyu.spike.wcl_activity_launchmode_demo/.MainActivity t2711}
  Stack #0:
    Running activities (most recent first):
      TaskRecord{27d796c9 #2695 A=com.miui.home U=0 sz=1}
        Run #0: ActivityRecord{2e5712cb u0 com.miui.home/.launcher.Launcher t2695}

ActivityManagerService类的调用过程:

  1. ActivityManagerService#startActivity
  2. ActivityManagerService#startActivityAsUser

ActivityManagerService调用ActivityStarterstartActivityMayWait方法, 执行启动.

@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) {
    // ...
    return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
            resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
            profilerInfo, null, null, bOptions, false, userId, null, null);
}

ActivityStarter类负责处理Activity的Intent和Flags的逻辑, 还有管理Stack和TaskRecord.

ActivityStarter类的调用流程:

  1. ActivityStarter#startActivityMayWait
  2. ActivityStarter#startActivityLocked
  3. ActivityStarter#startActivityUnchecked

startActivityMayWait: 根据Intent获取Activity的启动信息(ResolveInfo和ActivityInfo), 获取调用者的Pid和Uid.
startActivityLocked: 创建ActivityRecord, 含有Activity的核心信息.
startActivityUnchecked: 根据启动的Flag信息, 设置TaskRecord, 完成后执行ActivityStackSupervisor类的resumeFocusedStackTopActivityLocked方法, 继续启动.

private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
    // ...
    // 所有启动准备完成后, dontStart是true.
    final boolean dontStart = top != null && mStartActivity.resultTo == null
            && top.realActivity.equals(mStartActivity.realActivity)
            && top.userId == mStartActivity.userId
            && top.app != null && top.app.thread != null
            && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
            || mLaunchSingleTop || mLaunchSingleTask);
    if (dontStart) {
        ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
        // doResume是true, mDoResume也是true 
        if (mDoResume) {
            mSupervisor.resumeFocusedStackTopActivityLocked();
        }
        // ...
    }
    // ...
}

ActivityStackSupervisor类ActivityStack类配合使用. ActivityStackSupervisor负责管理Task和Stack, 而ActivityStack负责管理在Stack和Task中的Activity. 因此, 对于Stack和Task的操作, AMS使用ActivityStackSupervisor进行管理; 对于Activity的操作, AMS使用ActivityStack进行管理. 两者相互调用, 最终完成启动Activity.

ActivityStackSupervisor类ActivityStack类的调用流程:

  1. ActivityStackSupervisor#resumeFocusedStackTopActivityLocked
  2. ActivityStack#resumeTopActivityUncheckedLocked
  3. ActivityStack#resumeTopActivityInnerLocked
  4. ActivityStackSupervisor#startSpecificActivityLocked

核心在于ActivityStack类的resumeTopActivityInnerLocked方法, 根据ActivityRecord和ActivityOptions完成Activity的切换, 移至栈顶, 最后调用ActivityStackSupervisor类的startSpecificActivityLocked方法, 执行启动.

ActivityStackSupervisor类的startSpecificActivityLocked方法调用realStartActivityLocked方法, 执行真正的启动Activity.

void startSpecificActivityLocked(ActivityRecord r,
        boolean andResume, boolean checkConfig) {
    // 获取启动Activity的进程, 即Application
    ProcessRecord app = mService.getProcessRecordLocked(r.processName,
            r.info.applicationInfo.uid, true);
    r.task.stack.setLaunchTime(r);

    if (app != null && app.thread != null) {
        try {
            // ...
            // 真正启动Activity的过程
            realStartActivityLocked(r, app, andResume, checkConfig);
            return;
        }
        // ...
    }
    // ...
}

ActivityStackSupervisorrealStartActivityLocked方法中, 含有启动的核心方法scheduleLaunchActivity, 即调用IApplicationThreadscheduleLaunchActivity方法.

app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
        System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
        new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
        task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
        newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);

IApplicationThread的实现是ApplicationThread, 而ApplicationThread是ActivityThread的内部类, 即使用ApplicationThread类的scheduleLaunchActivity方法处理Activity启动.

最终由ActivityThread完成Activity的创建与绘制.


复杂的逻辑...

That's all! Enjoy it!

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

推荐阅读更多精彩内容