【Android源码系列】Activity启动源码解析,android mainactivity

426 阅读7分钟
原文链接: www.apkbus.com

                 一、前言         最近看《Android开发艺术探索》大多涉及到源码解析,仅仅看书有点云里雾里,于是配合着源码一起看感觉清晰许多。网上很多推荐source insight看源码,下来之后体验感觉一般,还不如AS直接看。老罗有专门的源码查看教学,但是需要Linux(Ubuntu)/MAC机器,暂时没条件以后考虑(老罗讲的比较深入,值得长期跟)。总之还是在AS里看(求推荐),强烈推荐浏览本文时和着源码。         二、源码解析         1、startActivityForResult
启动activity的方法最后都会走到startActivityForResult里。         
这里调用了Instrumentation的execStartActivity方法,我们直接跟进。

        
在Instrumentation里调用了ActivityManagerNative的getDefault()方法,getDefault返回了一个IActivityManager对象。

        
是一个单例对象,看到asInterface很熟悉(不熟悉的可以参考我的另一篇博客Android多进程IPC机制——binder原理探索)
IActivityManager其实就是binder接口,查看ActivityManagerNative代码发现他其实就是扮演正常IPC接口IActivityManager里的stub角色,这样的话需要一个实现这个stub接口的类来实现startActivity方法。
没错,他就是ActivityManagerService,我们进到startActivity,发现他直接丢给了startActivityAsUser,在里面又调用了ActivityStackSupervisor的startActivityMayWait方法,这里的跳转都很简单,我就不贴代码了。下面我们来看看startActivityMayWait。

[Java] 查看源文件 复制代码
final int startActivityMayWait(//参数省略) {
//我们只关心如何启动,部分检查判断代码省略,千万不要企图搞懂每一句代码的意思,有兴趣的话回头再过来看
int res = startActivityLocked(caller, intent, resolvedType, aInfo,voiceSession, voiceInteractor, resultTo, resultWho,requestCode, callingPid, callingUid, callingPackage,realCallingPid, realCallingUid, startFlags, options,componentSpecified, null, container, inTask);
}
        这里调用了startActivityLocked,而startActivityLocked里面又调用了startActivityUncheckedLocked,这个方法非常长,当时我是看晕了。这里我贴上关键代码。

经过一系列判断,调用了resumeTopActivitiesLocked方法,resumeTopActivitiesLocked里转给了ActivityStack的resumeTopActivityLocked方法。(这里其实可能调用ActivityStack的startActivityLocked方法,不过最终都会走到resumeTopActivityLocked)。在resumeTopActivityLocked内部又调用自己的resumeTopActivityInnerLocked方法,然后又回调了ActivityStackSupervisor的startSpecificActivityLocked方法:

        
直接走到realStartActivityLocked里,然后又一次的IPC通信,接口是IApplicationThread

        
这里调用了接口的scheduleLaunchActivity方法,和上一次一样,我们找到实现类ApplicationThread(是ActivityThread的内部类),以及他的scheduleLaunchActivity方法:

[Java] 查看源文件 复制代码
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
        ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
        String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
        PersistableBundle persistentState, List<ResultInfo> pendingResults,
        List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward,
        ProfilerInfo profilerInfo) {
    updateProcessState(procState, false);
    ActivityClientRecord r = new ActivityClientRecord();
    r.token = token;
    r.ident = ident;
    r.intent = intent;
    r.referrer = referrer;
    r.voiceInteractor = voiceInteractor;
    r.activityInfo = info;
    r.compatInfo = compatInfo;
    r.state = state;
    r.persistentState = persistentState;
    r.pendingResults = pendingResults;
    r.pendingIntents = pendingNewIntents;
    r.startsNotResumed = notResumed;
    r.isForward = isForward;
    r.profilerInfo = profilerInfo;
    updatePendingConfiguration(curConfig);
    sendMessage(H.LAUNCH_ACTIVITY, r);
}
        这个方法把传过来的参数包装成ActivityClientRecord ,通过sendMessage传出去,我们来看看这个sendMessage。         

        这里调用了mH的sendMessage方法,mH其实就是一个handler,我们看他如何处理数据:         
在里面调用了方法handleLaunchActivity。

[Java] 查看源文件 复制代码
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
//省略部分代码
 Activity a = performLaunchActivity(r, customIntent);
        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            Bundle oldState = r.state;
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed);
            if (!r.activity.mFinished && r.startsNotResumed) {
                try {
                    r.activity.mCalled = false;
                    mInstrumentation.callActivityOnPause(r.activity);
                    // part of stopping the activity.
                    if (r.isPreHoneycomb()) {
                        r.state = oldState;
                    }
                    if (!r.activity.mCalled) {
                        throw new SuperNotCalledException(
                            "Activity " + r.intent.getComponent().toShortString() +
                            " did not call through to super.onPause()");
                    }
                } catch (SuperNotCalledException e) {
                    throw e;
                } catch (Exception e) {
                    if (!mInstrumentation.onException(r.activity, e)) {
                        throw new RuntimeException(
                                "Unable to pause activity "
                                + r.intent.getComponent().toShortString()
                                + ": " + e.toString(), e);
                    }
                }
                r.paused = true;
            }
        } else {
            // If there was an error, for any reason, tell the activity
            // manager to stop us.
            try {
                ActivityManagerNative.getDefault()
                    .finishActivity(r.token, Activity.RESULT_CANCELED, null, false);
            } catch (RemoteException ex) {
                // Ignore
            }
        }
}
        终于,我们看见了activity的实例 [Java] 查看源文件 复制代码
Activity a = performLaunchActivity(r, customIntent);
        在这个方法里调用了activity的attach,以及生命周期oncreate。其他生命周期在上面代码里实现。         到这里,我们就理通了Activity的启动过程,主要还是利用IPC传递信息。
最后我推荐大家看源码时一定要做笔记,可以的话最好画图来帮助自己理清思路,不然会完全懵逼的。我目前使用startUML来画时序图,下面贴一张图。         

        怎么样,看到这张图感觉是不是整个流程清晰无比了?         哈哈,最后最后求查看源码方式,AS虽然勉强可以,但是也会经常找不到类很蛋疼。
        
            $(function () {
                $('pre.prettyprint code').each(function () {
                    var lines = $(this).text().split('\n').length;
                    var $numbering = $('').addClass('pre-numbering').hide();
                    $(this).addClass('has-numbering').parent().append($numbering);
                    for (i = 1; i