Activity启动的那些事

从安卓应用入口开始

  Activity的启动离不开ActivityThread。而ActivityThread的入口在main()方法:

public static void main(String[] args) {
        ......
        Looper.prepareMainLooper();
        ActivityThread thread = new ActivityThread();
        thread.attach(false);
        ......
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

  main()方法比较简单,首先准备MainLooper,也就是主线程的looper,然后创建ActivityThread对象,调用其attach方法。在创建ActivityThread对象时其实已经创建了主线程的handler,并绑定至当前的MainLooper。然后调用Looper.loop()。整个应用的循环开始。
  接下来追踪ActivityThread的attach方法:

private void attach(boolean system) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {//在main方法调用的attach走的这个if
            ViewRootImpl.addFirstDrawHandler(new Runnable() {
                @Override
                public void run() {
                    ensureJitEnabled();
                }
            });
            android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                    UserHandle.myUserId());
            RuntimeInit.setApplicationObject(mAppThread.asBinder());
            final IActivityManager mgr = ActivityManager.getService();//获取AMS的client
            try {
                mgr.attachApplication(mAppThread);
                //mAppThread其实是回调binder,也就是ApplicationThread作为Server端,由AMS回调Activity生命周期的方法。
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
            ......
        } else {//特殊情况
            android.ddm.DdmHandleAppName.setAppName("system_process",
                    UserHandle.myUserId());
            try {
                mInstrumentation = new Instrumentation();
                ContextImpl context = ContextImpl.createAppContext(
                        this, getSystemContext().mPackageInfo);
                mInitialApplication = context.mPackageInfo.makeApplication(true, null);
                mInitialApplication.onCreate();
            } catch (Exception e) {
                throw new RuntimeException(
                        "Unable to instantiate Application():" + e.toString(), e);
            }
        }
    ......
    }

  可以看到主要是获取了AMS的client(这里可以参考binder),然后给AMS设置Activity生命周期的回调。在ApplicationThread中主要是向主线程的handler发送各种Activity生命周期相关的消息。
  当启动一个activity时,startActivity方法最终会通过binder调用AMS上的activity启动方法,AMS最终会调用我们传给它的ApplicationThread回调,例如scheduleLaunchActivity方法(在ApplicationThread中具体实现,AMS作为client)。贯穿Activity启动始终的ActivityClientRecord也是在此创建:

@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);
        }

  然后会利用主线程handler处理相关的生命周期方法,例如handlerLaunchActivity:

                //对应的代码在ActivityThread的嵌套类H中,也就是主线程handler的定义中
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;

Activity的启动之路

  对于应用程序来说,真正的启动工作应该从handleLaunchActivity方法开始。那么这个方法做了哪些事情呢?

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
        // 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);//初始化并获得activity对象

        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            reportSizeConfigurations(r);
            Bundle oldState = r.state;
            //执行resume
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
            ......
    }

  这个方法主要对activity进行了初始化工作,后续的一系列关于activity的初始化也由此展开。

performLaunchActivity

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ......

        ContextImpl appContext = createBaseContextForActivity(r);//创建context
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();

            //利用mInstrumentation创建activity对象

            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
        }

        try {
            //创建application,如果为空就创建,否则直接返回,保证application的唯一。
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);

            ......

            if (activity != null) {
                ......
                appContext.setOuterContext(activity);
                //调用了activity的attach,在这个里面初始化window和WindowManager。
                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);
                .......
                if (r.isPersistable()) {//调用activity的onCreate方法
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                ......
                r.activity = activity;
                r.stopped = true;
                if (!r.activity.mFinished) {
                    activity.performStart();//执行onStart()
                    r.stopped = false;
                }
            }

                ......

            mActivities.put(r.token, r);//ActivityThread保存了所有的activity

        } catch (SuperNotCalledException e) {
            throw e;

        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to start activity " + component
                    + ": " + e.toString(), e);
            }
        }

        return activity;
    }

  在这个方法中做了几个比较有分量的事情,我们一步步来分析:

1.初始化context。
2.创建activity对象。
3.创建application。
4.调用Activity的attach方法。
初始化context

  首先来看一下context是怎么初始化的。

//在performLaunchActivity中调用的创建context方法
private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
        final int displayId;
        try {
            //r。token是一个IBinder,应该是包含当前activity对应的一些信息以便AMS进行查找。
            displayId = ActivityManager.getService().getActivityDisplayId(r.token);//从AMS获取displayId。
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }

        ContextImpl appContext = ContextImpl.createActivityContext(
                this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);

        ......
        return appContext;
    }

//被createBaseContextForActivity调用的方法
static ContextImpl createActivityContext(ActivityThread mainThread,
            LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId,
            Configuration overrideConfiguration) {
        if (packageInfo == null) throw new IllegalArgumentException("packageInfo");

        String[] splitDirs = packageInfo.getSplitResDirs();
        ClassLoader classLoader = packageInfo.getClassLoader();

        ......
        //创建对象
        ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName,
                activityToken, null, 0, classLoader);

        // Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY.
        displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY;

        final CompatibilityInfo compatInfo = (displayId == Display.DEFAULT_DISPLAY)
                ? packageInfo.getCompatibilityInfo()
                : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;

        final ResourcesManager resourcesManager = ResourcesManager.getInstance();

        // Create the base resources for which all configuration contexts for this Activity
        // will be rebased upon.
        //做一些初始化设置
        context.setResources(resourcesManager.createBaseActivityResources(activityToken,
                packageInfo.getResDir(),
                splitDirs,
                packageInfo.getOverlayDirs(),
                packageInfo.getApplicationInfo().sharedLibraryFiles,
                displayId,
                overrideConfiguration,
                compatInfo,
                classLoader));
        context.mDisplay = resourcesManager.getAdjustedDisplay(displayId,
                context.getResources());
        return context;
    }

  以上就是context创建相关过程。从代码上来看,这里的context和activity,displayId有比较强的关联。应该是与资源管理相关的context。

初始化activity对象

  activity对象的创建是调用的mInstrumentation.newActivity方法。
  那么先去看看mInstrumentation是何方神圣。其初始化的位置有两处,一处是在ActivityThread的attach方法中,当参数为true时直接初始化

private void attach(boolean system) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {
            ......
        } else {
            // Don't set application object here -- if the system crashes,
            // we can't display an alert, we just want to die die die.
            android.ddm.DdmHandleAppName.setAppName("system_process",
                    UserHandle.myUserId());
            try {
                mInstrumentation = new Instrumentation();//直接新建对象
                ContextImpl context = ContextImpl.createAppContext(
                        this, getSystemContext().mPackageInfo);//顺便初始化AppContext
                mInitialApplication = context.mPackageInfo.makeApplication(true, null);
                mInitialApplication.onCreate();//顺便初始化Application
            } catch (Exception e) {
                throw new RuntimeException(
                        "Unable to instantiate Application():" + e.toString(), e);
            }
        }

        ......
    }

  但是这不是我们平常初始化activity的流程,因此要看另一处,ActivityThread的handleBindApplication方法:

private void handleBindApplication(AppBindData data) {
    ......
    final InstrumentationInfo ii;
    if (data.instrumentationName != null) {
            try {
                ii = new ApplicationPackageManager(null, getPackageManager())
                        .getInstrumentationInfo(data.instrumentationName, 0);
            } catch (PackageManager.NameNotFoundException e) {
                throw new RuntimeException(
                        "Unable to find instrumentation info for: " + data.instrumentationName);
            }

            ......
        } else {
            ii = null;
        }

        //创建AppContext
        final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
        updateLocaleListFromAppContext(appContext,
                mResourcesManager.getConfiguration().getLocales());
    ......
    if (ii != null) {
            //创建Application
            final ApplicationInfo instrApp = new ApplicationInfo();
            ii.copyTo(instrApp);
            instrApp.initForUser(UserHandle.myUserId());
            final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
                    appContext.getClassLoader(), false, true, false);
            final ContextImpl instrContext = ContextImpl.createAppContext(this, pi);

            try {
                final ClassLoader cl = instrContext.getClassLoader();
                mInstrumentation = (Instrumentation)
                    cl.loadClass(data.instrumentationName.getClassName()).newInstance();//新建对象
            } catch (Exception e) {
                throw new RuntimeException(
                    "Unable to instantiate instrumentation "
                    + data.instrumentationName + ": " + e.toString(), e);
            }

            ......
        } else {
            mInstrumentation = new Instrumentation();
        }
        ......

}

  这个方法是在handler中被调用的,根据前面的分析,有可能是AMS调用的。事实上确实如此。在ActivityThread的main方法中调用了ActivityThread的attach方法,attach方法中会调用AMS的attachApplication方法。这个方法就是告诉AMS我的ActivityThread已经创建好了,然后AMS会回调ActivityThread的bindApplication方法,接着就到了handler发消息,然后就到了我们看到的这个方法。大概做了三件事,初始化context,初始化application,初始化mInstrumentation。
  好了,绕了一大圈,下面就要看一下activity到底是怎么被创建的了。经过上面的分析,我们知道这个时候Application和context已经被创建了。下面是mInstrumentation的newActivity方法:

public Activity newActivity(ClassLoader cl, String className,
            Intent intent)
            throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
        return (Activity)cl.loadClass(className).newInstance();
    }

  感觉有点失望,竟然是直接就创建了一个activity。没关系,继续往下看。

创建Application

  经过上面的分析,发现在创建mInstrumentation的时候就已经创建了Application,那么这里为什么还要创建呢?是不是创建了多个Application?对比一下两个创建方法就知道了。

public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        if (mApplication != null) {
            return mApplication;
        }

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");

        Application app = null;

        String appClass = mApplicationInfo.className;
        if (forceDefaultAppClass || (appClass == null)) {
            appClass = "android.app.Application";
        }

        try {
            java.lang.ClassLoader cl = getClassLoader();
            if (!mPackageName.equals("android")) {
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                        "initializeJavaContextClassLoader");
                initializeJavaContextClassLoader();
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            }
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        } catch (Exception e) {
            if (!mActivityThread.mInstrumentation.onException(app, e)) {
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                throw new RuntimeException(
                    "Unable to instantiate application " + appClass
                    + ": " + e.toString(), e);
            }
        }
        mActivityThread.mAllApplications.add(app);
        mApplication = app;

        if (instrumentation != null) {
            try {
                instrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
                if (!instrumentation.onException(app, e)) {
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    throw new RuntimeException(
                        "Unable to create application " + app.getClass().getName()
                        + ": " + e.toString(), e);
                }
            }
        }

        // Rewrite the R 'constants' for all library apks.
        SparseArray<String> packageIdentifiers = getAssets().getAssignedPackageIdentifiers();
        final int N = packageIdentifiers.size();
        for (int i = 0; i < N; i++) {
            final int id = packageIdentifiers.keyAt(i);
            if (id == 0x01 || id == 0x7f) {
                continue;
            }

            rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);
        }

        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

        return app;
    }

  它们调用的都是LoadApk的makeApplication方法,那么看一下在哪里调用的,追踪到最顶部,发现在主线程的handler里面:

......
case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;
......
case BIND_APPLICATION:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
                    AppBindData data = (AppBindData)msg.obj;
                    handleBindApplication(data);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
......

//这是handleBindApplication方法中获取LoadApk的方法。
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);

  可以发现都是调用的同一个方法,参数是app相关的信息,并且从AMS传递而来。几乎可以确定是同一个对象的makeApplication方法。因此Application只会创建一次。多次调用的原因可能是保证其一定被创建。

调用activity的attach方法

  activity的attach方法中主要是创建Window和WindowManager以及绑定与activity相关的一连串变量,在我的这篇博客中有分析。

handleResumeActivity

  handleResumeActivity如下:

final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
        ActivityClientRecord r = mActivities.get(token);
        if (!checkAndUpdateLifecycleSeq(seq, r, "resumeActivity")) {
            return;
        }

        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();
        mSomeActivitiesChanged = true;

        // TODO Push resumeArgs into the activity for consideration
        r = performResumeActivity(token, clearHide, reason);//performResumeActivity,执行一些生命周期的方法。最终会调用activity的onResume方法。

        if (r != null) {
            final Activity a = r.activity;
            ......
            if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow();//在Activity的attach方法中初始化完毕。
                View decor = r.window.getDecorView();//初始化DecorView
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager();//在Activity的attach方法中初始化完毕。
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (r.mPreserveWindow) {
                    a.mWindowAdded = true;
                    r.mPreserveWindow = false;
                    // Normally the ViewRoot sets up callbacks with the Activity
                    // in addView->ViewRootImpl#setView. If we are instead reusing
                    // the decor view we have to notify the view root that the
                    // callbacks may have changed.
                    ViewRootImpl impl = decor.getViewRootImpl();
                    if (impl != null) {
                        impl.notifyChildRebuilt();
                    }
                    if (a.mVisibleFromClient) {
                    if (!a.mWindowAdded) {
                        a.mWindowAdded = true;
                        wm.addView(decor, l);//绑定window和根view,以及建立和RootViewImpl的关系,并开始绘制流程。
                        }
                        ......
                    }
                }
                ......

            // If the window has already been added, but during resume
            // we started another activity, then don't yet make the
            // window visible.
            } else if (!willBeVisible) {
                if (localLOGV) Slog.v(
                    TAG, "Launch " + r + " mStartedActivity set");
                r.hideForNow = true;
            }

            // Get rid of anything left hanging around.
            cleanUpPendingRemoveWindows(r, false /* force */);

            ......
    }

  从performResumeActivity的代码大致可以看出来其主要做了两件事:

1.调用performResumeActivity方法。
2.初始化window并与activity建立关联。

  下面先来看一下performResumeActivity做了些什么事情。

public final ActivityClientRecord performResumeActivity(IBinder token,
            boolean clearHide, String reason) {
        ActivityClientRecord r = mActivities.get(token);
        if (localLOGV) Slog.v(TAG, "Performing resume of " + r
                + " finished=" + r.activity.mFinished);
        if (r != null && !r.activity.mFinished) {
            if (clearHide) {
                r.hideForNow = false;
                r.activity.mStartedActivity = false;
            }
            try {
                ......
                r.activity.performResume();//调用activity的performResume方法。

                ......
            } catch (Exception e) {
                if (!mInstrumentation.onException(r.activity, e)) {
                    throw new RuntimeException(
                        "Unable to resume activity "
                        + r.intent.getComponent().toShortString()
                        + ": " + e.toString(), e);
                }
            }
        }
        return r;
    }

  可以看到主要调用了activity的performResume方法。继续往下看:

final void performResume() {
        performRestart();//如果之前app执行了onStop()则执行onRestart(),onStart();

        mFragments.execPendingActions();

        mLastNonConfigurationInstances = null;

        mCalled = false;
        mInstrumentation.callActivityOnResume(this);//执行onResume()
        ......

        mCalled = false;

        mFragments.dispatchResume();
        mFragments.execPendingActions();
        ......
    }

  由此可见,从上面的handleLaunchActivity的执行顺序来看,也的确是和Activity的启动顺序相符合的:首先执行performLaunchActivity,在这期间创建了Activity,创建了Window,以及Application和context等,然后调用onCreate方法。onCreate方法之后会调用onStart方法,接着执行handleResumeActivity方法,首先会执行onResume等生命周期方法,然后才是创建DecorView,创建ViewRootImpl再执行测量,绘制等工作。

因此我们在onCreate或者onResume中是无法获取控件的宽高度的。

  相对于生命周期方法来说,测量和绘制是在最后执行的。
  从上面的分析还可以发现一个有趣的地方:

activity的生命周期方法的调用交给了一个特殊的类Instrumentation去处理。

  不仅仅是生命周期方法,包括startActivity等方法最终也都是在这个对象中完成的调用。
  这种能解耦的方式和代码习惯还是值得我们多多学习。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值