安卓开发Android开发进阶经验分享首页投稿(暂停使用,暂停投稿)

Activity的启动过程分析

2016-03-27  本文已影响690人  tmp_zhao

缘起

我们在平时开发中都知道通过这样的代码就可以启动一个act,如下Context.startActivity(intent),但是你偶尔有没有想过它内部是如何实现的,或者说系统究竟干了哪些事情,怎么这个act就显示在用户面前呢?作为一个资深工程师我觉得你起码应该想过这个问题,下面我们一起来梳理下整个流程,以下分析基于6.0源码。

在开始之前我还想啰嗦几句,其实启动一个act的过程,是一个标准的Android IPC过程,也就是通过Binder机制实现的跨进程通信,先预告下,后面慢慢细说。

过程分析

  1. 一般我们都是通过调用Activity.startActivity(intent)来启动一个act的,紧接着它会调用其内部的startActivityForResult(intent, -1, null )方法,注意这里的requestCode==-1,因为我们不需要返回result;
  2. 接下来调用到了Instrumentation.execStartActivity()方法,它最终调用了如下代码:
    execStartActivity()方法
  3. 上面的ActivityManagerNative.getDefault().startActivity实际通过Binder机制调到了
    另一个进程中的AMS.startActivity方法,代码如下:
    server/am/ActivityManagerService.java
    接下来在AMS这边的调用流程这里简要罗列下,具体实现细节可以参考源码,流程如下:
ActivityStackSupervisor.startActivityMayWait -->    
ActivityStackSupervisor.startActivityLocked -->
ActivityStackSupervisor.startActivityUncheckedLocked -->
ActivityStack.resumeTopActivitiesLocked -->
ActivityStack.resumeTopActivityInnerLocked -->
ActivityStackSupervisor.startSpecificActivityLocked -->
ActivityStackSupervisor.realStartActivityLocked

最终在ActivityStackSupervisor.realStartActivityLocked里有这样的代码:

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

这段代码很关键,这里app.thread的类型为android.app.IApplicationThread,其源码大概是这个样子:

IApplicationThread.java
  1. IApplicationThread的真正实现者就是客户端进程中ActivityThread的内部类ApplicationThread,我们去看眼其实现:


    ApplicationThread实现

    绕了一个大圈子,activity的启动流程终于又回到客户端进程了,我们看下ApplicationThread.scheduleLaunchActivity的实现:

        @Override
        public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
                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;

            r.overrideConfig = overrideConfig;
            updatePendingConfiguration(curConfig);

            sendMessage(H.LAUNCH_ACTIVITY, r);
        }

可以看到代码主要是用传进来的参数构造了一个ActivityClientRecord实例,然后发送了一个LAUNCH_ACTIVITY的msg;

  1. 对此消息的处理实质是调用了ActivityThread.handleLaunchActivity方法,代码如下:
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();
        mSomeActivitiesChanged = true;

        if (r.profilerInfo != null) {
            mProfiler.setProfiler(r.profilerInfo);
            mProfiler.startProfiling();
        }

        // Make sure we are running with the most recent config.
        handleConfigurationChanged(null, null);

        if (localLOGV) Slog.v(
            TAG, "Handling launch of " + r);

        // Initialize before creating the activity
        WindowManagerGlobal.initialize();

        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) {
                // The activity manager actually wants this one to start out
                // paused, because it needs to be visible but isn't in the
                // foreground.  We accomplish this by going through the
                // normal startup (because activities expect to go through
                // onResume() the first time they run, before their window
                // is displayed), and then pausing it.  However, in this case
                // we do -not- need to do the full pause cycle (of freezing
                // and such) because the activity manager assumes it can just
                // retain the current state it has.
                try {
                    r.activity.mCalled = false;
                    mInstrumentation.callActivityOnPause(r.activity);
                    // We need to keep around the original state, in case
                    // we need to be created again.  But we only do this
                    // for pre-Honeycomb apps, which always save their state
                    // when pausing, so we can not have them save their state
                    // when restarting from a paused state.  For HC and later,
                    // we want to (and can) let the state be saved as the normal
                    // 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
            }
        }
    }

通过其源码我们发现,它又将重任交给了performLaunchActivity方法,这个方法主要做了以下几件事情:
1. 从ActivityClientRecord中获取待启动act的组件信息;
2. 通过Instrumentation.newActivity方法使用ClassLoader创建act对象;
3. 通过LoadedApk.makeApplication方法创建Application对象,注意如果已经有Application对象的话是不会再次创建的;
4. 创建ComtextImpl对象,并调用Activity.attach方法完成一些重要数据的初始化操作;
5. 最终调用Activity.onCreate()方法;

至此,act的整个启动流程就走完了。

总结

平时对于我们开发人员来说,可能还是最后这块客户端部分的代码比较
有用,非常有助于我们的理解,特别是对performLaunchActivity的源码,有空的话还需要细细品味啊。

注:关于这里第5步更详细的文章见这里ActivityThread.handleLaunchActivity方法分析

上一篇下一篇

猜你喜欢

热点阅读