【Android组件内核面试题请描诉Activity的启动流程,从点击图标开始

2023年 9月 30日 28.9k 0

请描诉Activity的启动流程,从点击图标开始。(B站)

这道题想考察什么?
  • 是否了解启动流程的知识?
  • 考察的知识点
  • Binder的运用
  • AMS的理解
  • ActivityThread、ApplicationThread的理解
  • Instrumentation的运用
  • 考生应该如何回答

    注意: 本文中涉及ActivityThread、ApplicationThread、Binder、Instrumentation知识,如果对上述概念不熟悉的同学,先学习对应章节。

    1.重要类的简单介绍
    • ActivityManagerService (简称AMS),运行于system_server 进程,其核心为一个Binder服务端,与之对应的是 ActivityManagerProxy(简称AMP),运行在各个应用即客户端,封装了Binder操作,应用使用这个类远程调用AMS
    • ActivityThread,App的入口类,其main方法为应用进程java层的起点,完成启动初始化工作,并通过Binder和Handler负责应用与system_server进程间通信的消息转发工作
    • ApplicationThread,工作在应用进程,ActivityThread的成员变量,负责应用和system_server间的通信,与AMS功能对应,其作为Binder服务端,system_server通过ApplicationThreadProxy远程调用ApplicationThread,从而执行ActivityThread的各个方法,经过ActivityThread的转发,从而控制整个应用
    • Instrumentation,ActivityThread对Activity生命周期的调用具体通过这个类实现

    以下我们通过Launcher启动一个应用来演示一个应用的启动过程:

    startActivity

    ​ 通过Launcher启动一个Activity,此时这个Activity所需要依附的进程还未启动:

    ​ 首先我们在Launcher的主线程(即所谓UI线程)里执行startActivity,这个方法最后通过Instrumentation执行ActivityManagerProxy的同名方法,通过AMP远程执行AMS(ActivityManagerService的同名方法),

    ​ 打印main 线程的调用栈,执行从下到上,Activity的startActivity方法最终执行了AMP的startActivity,作为Binder客户端这个startActivity的实现就是打包各种参数并传到Binder驱动

    main:

     在这里插入图片描述

    showStartingWindow

    调到这里,因为AMS和AMP是实现了同一个接口的,所以在AMS作为服务端也有同名方法,下面是在system_server进程中,一个被启动来处理这个消息的Binder线程的调用栈:

    在这里插入图片描述

    可以看到Binder在倒数第四行,执行了startActivity,下面三个函数启动的作用就是取出并解析传过来的数据,然后交付给对应的方法处理,这里根据传过来的方法id执行到了ActivityManagerService的startActivity方法,再经过层层调用,通知WMS显示startingWindow,所谓startingWindow,就是系统为了应用之间的过渡平滑,应用在启动之前,预先启动起来的预览视图,这是应用的MainActivity的theme里面配置的,这个视图的显示速度非常快,因为其不属于应用进程,不需要等待应用初始化,往往在点击应用图标的瞬间就能显示。

    schedulePauseActivity

    再看这次调用中另一个方法的调用栈:

    在这里插入图片描述

    调到了ApplicationThreadProxy(ATP)的schedulePauseActivity方法,看名字,就知道这又是一个Binder客户端,这个Binder客户端对应的Binder服务端在Launcher的进程里,名字叫ApplicationThread,system_server进程通过这个ATP可以跨进程调用Launcher的方法(每个应用进程都有一个ApplicationThread,有次可以得出system_server进程存有所有由它管理的进程的ATP,因为它必须通过这些ATP去管理所有应用进程,如控制应用组件的生命周期),到这里,整个调用链从Launcher进程的main线程,再到system_server进程,现在又要回到Launcher,但是要注意,通过Binder再调回去之后,ApplicationThread的schedulepauseActivity方法就是在一个另起的Binder线程里了,main线程会继续执行它后续的指令不受影响,我们现在查看Launcher里面这个另起的Binder线程的调用栈:

    在这里插入图片描述

    这里可以看到,在ApplicationThread的schedulepauseActivity方法里的处理,Binder线程往Handler里发送了一条消息,这个消息将由main线程来处理

    activityPaused

    此时我们查看主线程接收这个这个message之后的处理:

    在这里插入图片描述

    可以看到收到在handleMessage里,主线程执行了ActivityThread的handlePauseActivity,我们来看一下handlePauseActivity的实现,下面是几行核心代码:

       performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity");
                    ...
                    ...
                // Tell the activity manager we have paused.
                if (!dontReport) {
                    try {
                        ActivityManagerNative.getDefault().activityPaused(token);
                    } catch (RemoteException ex) {
                        throw ex.rethrowFromSystemServer();
                    }
                }
    

    performPauseActivity最终会执行到Activity的onPause方法(在这之前还会先调用Fragment的onPause),然后执行到ActivityManagerNative.getDefault().activityPaused(token) 也就是我们上图调用栈所示的AMP的activityPaused方法。

    到这里,整个流程还没有走到一个新的Activity的创建甚至连新的应用进程都还没有创建,Launcher与system_server两个进程之间已经经过了来回各一次跨进程的调用。而到现在对应用开发者能实际感知的到的很重要的一点,就是当前Activity和Fragment走到到了生命周期onPause。应用开发者该在这里做状态保存工作了。

    Process.start

    回到AMP的activityPaused方法,现在Launcher的主线程是需要远程调用AMS,system_server端会把这个调用交个一个空闲Binder线程去处理,我们查看其调用栈:

    在这里插入图片描述

    注意 ActivityStackSupervisor中的startSpecificActivityLocked方法,这个方法在这里会进入分岔路口,这里会检查这个Activity需要依附的进程有没有被创建,如果已经创建,则会进入realStartActivityLocked方法,远程执行Launcher进程,实例化要启动的Activity,并依次调用其onCreate,onStart,onResume生命周期方法(当然其中各个方法的调用都是经过各个类层层调用,但如果从应用开发的角度来说就是这个执行顺序,期间不需要再由AMS干预),但对应进程如果不存在,则还需要执行AMS的startProcess创建这个进程,如上调用栈栈顶走到Process类的start方法,注意执行这个方法时传递的一个参数,entryPoint,这里是android.app.ActivityThread

        // Start the process.  It will either succeed and return a result containing
                // the PID of the new process, or else throw a RuntimeException.
                boolean isActivityProcess = (entryPoint == null);
                if (entryPoint == null) entryPoint = "android.app.ActivityThread";
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                        app.processName);
                checkTime(startTime, "startProcess: asking zygote to start proc");
                Process.ProcessStartResult startResult = Process.start(entryPoint,
                        app.processName, uid, uid, gids, debugFlags, mountExternal,
                        app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                        app.info.dataDir, entryPointArgs);
                checkTime(startTime, "startProcess: returned from zygote!");
    

    传递这个参数,新进程在启动之后就会执行这个类的main方法作为java层的起点(java层第一个方法应该是ZygoInit的main,但在调用栈中根据传过来的参数分成别反射执行了SystemServer和ActiviThread的main,我们习惯上把这两个函数当成起点),至于Process.start的实现,这里先不深究,大致过程,zygote进程与system_server之间通过socket通信,要创建进程时,system_server 进程里通过往socket写入消息,zygote接收到消息后fork出一个进程,最终会执行ActivityThread的main函数,下面看一下创建进程需要的参数:

         * Starts a new process via the zygote mechanism.
         *
         * @param processClass Class name whose static main() to run
         * @param niceName 'nice' process name to appear in ps
         * @param uid a POSIX uid that the new process should setuid() to
         * @param gid a POSIX gid that the new process shuold setgid() to
         * @param gids null-ok; a list of supplementary group IDs that the
         * new process should setgroup() to.
         * @param debugFlags Additional flags.
         * @param targetSdkVersion The target SDK version for the app.
         * @param seInfo null-ok SELinux information for the new process.
         * @param abi the ABI the process should use.
         * @param instructionSet null-ok the instruction set to use.
         * @param appDataDir null-ok the data directory of the app.
         * @param extraArgs Additional arguments to supply to the zygote process.
         * @return An object that describes the result of the attempt to start the process.
         * @throws ZygoteStartFailedEx if process start failed for any reason
         */
    

    其实现:

      /**
                 * See com.android.internal.os.ZygoteInit.readArgumentList()
                 * Presently the wire format to the zygote process is:
                 * a) a count of arguments (argc, in essence)
                 * b) a number of newline-separated argument strings equal to count
                 *
                 * After the zygote process reads these it will write the pid of
                 * the child or -1 on failure, followed by boolean to
                 * indicate whether a wrapper process was used.
                 */
                final BufferedWriter writer = zygoteState.writer;
                final DataInputStream inputStream = zygoteState.inputStream;
                writer.write(Integer.toString(args.size()));
                writer.newLine();
                for (int i = 0; i < sz; i++) {
                    String arg = args.get(i);
                    writer.write(arg);
                    writer.newLine();
                }
                writer.flush();
                ---
                ---
                // Always read the entire result from the input stream to avoid leaving
                // bytes in the stream for future process starts to accidentally stumble
                // upon.
                result.pid = inputStream.readInt();
                result.usingWrapper = inputStream.readBoolean();
    

    往流里写入值各种参数,再从流里读回返回信息,具体的实现就是zygote进程的事了。

    至此,一个应用进程就已经启动,我们进入android.app.ActivityThread的main方法,我们可以当这里是应用的起点。

    ActivityThread.main

    从 ActivityThread 的main方法开始,应用进入 java 层,应用在main里面的核心代码:

        public static void main(String[] args) {
            ... ...
            Looper.prepareMainLooper();
            ActivityThread thread = new ActivityThread();
            thread.attach(false);
            ... ...
            Looper.loop();
        }
    

    主要的三件事:

  • 调用Looper.prepareMainLooper 创建mainLooper并赋值给Loop (这个looper的MessageQueue不能quit)静态变量 sMainLooper ,这样应用可以在任何地方拿到主线程的Looper
  • 创建ActivityThread实例,并执行attach,这两步很关键,首先,ActivityThread对象创建时,会创建ResourcesManager的单例对象,还会创建 ApplicationThread 对象作为匿名Binder服务端用以跟system_server进程通信,在thread.attach(false) 中通过AMP把 这个对象注册到AMS:
  •   final IActivityManager mgr = ActivityManagerNative.getDefault();
        try {
            mgr.attachApplication(mAppThread);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    

    AMS 对各应用组件的生命周期管理就是通过这个对象实现的,AMS会通过这个ApplicationThread 对象远程调用应用进程的方法从而实现管理。

    另外在attach 方法里ActivityThread对象会把自己赋值给静态变量sCurrentActivityThread,在应用开发中可以通过反射ActivityThread 直接拿到这个静态变量对象或反射后执行静态方法 currentActivityThread()拿到应用的ActivityThread 对象,从而可以拿到其成员变量mAppThread,mInstrumentation,插件化方案可能需要hook这两个对象。

  • 主线程启动loop,进入循环,等待其他线程往消息队列里发消息
  • attachApplication

    远程执行AMS的attachApplication方法后,会调用到系统进场中AMS的attachApplicationLocked,通过ProcessRecord.makeActive将这个IApplicationThread 传入与进程相关的ProcessRecord,这个对象与每个用户进程相对应, 这样system_server进程就持有了应用的一个Binder,之后就可以通过这个Binder给应用发消息,从而管理应用了。

    bindApplication

    之后system_server进程通过thread.bindApplication远程调用应用进程的ApplicationThread的同名方法,同之前的其他调用,应用进程里bindApplication这个方法是运行在某个binder线程的,这里这个Binder线程调用这个方法通过handler即成员变量mH把消息丢给了主线程,主线程收到消息转到ActivityThread的handleBindApplication方法,查看调用栈

    system_server:

    在这里插入图片描述

    从attachApplication 调用到 bindApplication,整个执行过程由应用发起,将ApplicationThread传递给AMS(attachApplication这个方法最主要的功能就是把ApplicatioThread传递给了system_server进程,从此应用进程和system_server进程可以互相通信),然后AMS拿到这个ApplicationThread的客户端ATP,执行其bindApplication,这样调用又走回了应用,应用会在bindApplication里面做一些初始化工作,例如实例化Instrumentation,实例化Application,并赋值给mInitialApplication = app;这个变量的赋值是唯一的,只会有这一次,也就是一个进程应用进程只会有一个mInitialApplication,但是,这并不意味着一个进程只有一个Application实例,一个进程里是有可能创建多个Application实例的,比如下面要讲的handleLaunchActivity方法,每运行一个Activity,都会去判断这个Activity对应的Application有没有被实例化,若没有,则会创建,并添加到mAllApplications列表,这种情况会在两个应用共用进程时出现。mInitialApplication赋值后,会作为参数启动provider。

    bindApplication:

     // Allow disk access during application and provider setup. This could
            // block processing ordered broadcasts, but later processing would
            // probably end up doing the same disk access.
            final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
            try {
                // If the app is being launched for full backup or restore, bring it up in
                // a restricted environment with the base application class.
              //这里只会实例化Application,而不会调用其onCreate
                Application app = data.info.makeApplication(data.restrictedBackupMode, null);
                mInitialApplication = app;
    
                // don't bring up providers in restricted mode; they may depend on the
                // app's custom Application class
                if (!data.restrictedBackupMode) {
                    if (!ArrayUtils.isEmpty(data.providers)) {
                        //初始化ContentProvider
                        installContentProviders(app, data.providers);
                        // For process that contains content providers, we want to
                        // ensure that the JIT is enabled "at some point".
                        mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
                    }
                }
    
                // Do this after providers, since instrumentation tests generally start their
                // test thread at this point, and we don't want that racing.
                try {
                    mInstrumentation.onCreate(data.instrumentationArgs);
                }
                catch (Exception e) {
                    throw new RuntimeException(
                        "Exception thrown in onCreate() of "
                        + data.instrumentationName + ": " + e.toString(), e);
                }
    
                try {
                  //调用Application.onCreate
                    mInstrumentation.callApplicationOnCreate(app);
                } catch (Exception e) {
                    if (!mInstrumentation.onException(app, e)) {
                        throw new RuntimeException(
                            "Unable to create application " + app.getClass().getName()
                            + ": " + e.toString(), e);
                    }
                }
            } finally {
                StrictMode.setThreadPolicy(savedPolicy);
            }
    
        private void installContentProviders(
                Context context, List providers) {
            final ArrayList results =
                new ArrayList();
    
            for (ProviderInfo cpi : providers) {
                if (DEBUG_PROVIDER) {
                    StringBuilder buf = new StringBuilder(128);
                    buf.append("Pub ");
                    buf.append(cpi.authority);
                    buf.append(": ");
                    buf.append(cpi.name);
                    Log.i(TAG, buf.toString());
                }
              //这个context就是mInitialApplication,这里会实例化provider
              //installProvider方法里会为每个provider赋值一个context,这个Context有可能是                   //mInitialApplication本身,也可能是根据不同包名重新创建的
              //这个方法里还会调用ContentProvider的onCreate生命周期方法
              //要注意,直到这里,我们还在ActivityThread的bindApplication方法里,这是AMS对应用进程的第          //一个远程调用,我们虽然已经创建了Application实例,但我们还没有调用其onCreate,还没有任何          //Activity和Service组件被实例化,而在这里,所有ContentProvider已经完成创建,调用                //onCreate并注册到AMS了
                IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
                        false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
                if (cph != null) {
                    cph.noReleaseNeeded = true;
                    results.add(cph);
                }
            }
            //注册到AMS
            try {
                ActivityManagerNative.getDefault().publishContentProviders(
                    getApplicationThread(), results);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }
    

    bindApplication完成后,到这里应用进程已经先后完成了Application的实例化,ContentProvider的实例化和onCreate生命周期,Application的onCreate生命周期。

    scheduleLaunchActivity

    注意AMS里面 attachApplicationLocked方法,除了远程执行ActivityThread的bindApplication外,还执行了其scheduleLaunchActivity方法,这个方法最终会实例化一个Activity,调用其生命周期方法。先来看system_server端的调用栈:

    在这里插入图片描述

    下面是上面两次远程调用,转到应用进程后对应的两次处理,都是Binder线程收到消息后重新丢到主线程里后主线程的调用栈。

    在这里插入图片描述

    在这里插入图片描述

    handleLaunchActivity是应用进程收到的第二个system_server的远程调用(通过handler中转过的),我们来看一下主线程在handleLaunchActivity里做了什么:

     // Make sure we are running with the most recent config.
            handleConfigurationChanged(null, null);
            ... ...
            // Initialize before creating the activity
            WindowManagerGlobal.initialize();
    
            Activity a = performLaunchActivity(r, customIntent);
            if (a != null) {
                r.createdConfig = new Configuration(mConfiguration);
                reportSizeConfigurations(r);
                Bundle oldState = r.state;
                handleResumeActivity(r.token, false, r.isForward,
                        !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
                ... ...
            }
    

    performLaunchActivity得到了一个Activity,之后执行了handleResumeActivity,这里方法里就会执行Activity的onResume生命周期方法。再看在这之前performLaunchActivity的逻辑:

     Activity activity = null;
            try {
              //反射实例化Activity
                java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
                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之前没有创建
              //则会先实例化,这种情况出现在一个应用进程承载多个应用时,启动第一个之外的其他应用时应用进程
              //已经创建并与AMS绑定,所以不会走bindApplication方法,所以新应用对应的Application是还没有
              //创建的,需要先创建。
                Application app = r.packageInfo.makeApplication(false, mInstrumentation);
                ... ...
                if (activity != null) {
                  //这里实际是一个ContextImpl实例
                    Context appContext = createBaseContextForActivity(r, activity);
                    CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                    Configuration config = new Configuration(mCompatConfiguration);
                    if (r.overrideConfig != null) {
                        config.updateFrom(r.overrideConfig);
                    }
                    if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                            + r.activityInfo.name + " with config " + config);
                    Window window = null;
                    if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                        window = r.mPendingRemoveWindow;
                        r.mPendingRemoveWindow = null;
                        r.mPendingRemoveWindowManager = null;
                    }
                    //典型装饰者模式,Activity的很多功能会委托给ContextImpl实例实现
                    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);
    
                    if (customIntent != null) {
                        activity.mIntent = customIntent;
                    }
                    r.lastNonConfigurationInstances = null;
                    activity.mStartedActivity = false;
                    int theme = r.activityInfo.getThemeResource();
                    if (theme != 0) {
                        activity.setTheme(theme);
                    }
    
                    activity.mCalled = false;
                  
                  //调用Activity.onCreate
                    if (r.isPersistable()) {
                        mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                    } else {
                        mInstrumentation.callActivityOnCreate(activity, r.state);
                    }
                  ... ...
                    //Activity.onStart
                    if (!r.activity.mFinished) {
                        activity.performStart();
                        r.stopped = false;
                    }
                  ///Activity.onRestoreInstanceState
                    if (!r.activity.mFinished) {
                        if (r.isPersistable()) {
                            if (r.state != null || r.persistentState != null) {
                                mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                                        r.persistentState);
                            }
                        } else if (r.state != null) {
                            mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                        }
                    }
    

    利用Instrumentation反射创建Activity,然后r.packageInfo.makeApplication(false, mInstrumentation),这个方法会判断当前应用(注意是应用而不是进程)有没有Application实例,若没有,则创建,创建其ContextImpl,调用其生命周期方法onCreate,注意Application app = r.packageInfo.makeApplication(false, mInstrumentation); 这个方法,其实现末尾处有一段判断

        if (mApplication != null) {
                return mApplication;//这里作为应用进程第一个被创建的Application,在bindApplication里就完成了实例化和生命周期onCreate,这里直接返回
            }
            //这里省略了反射实例化Application的代码
            ... ...
            if (instrumentation != null) {
                try {
                    instrumentation.callApplicationOnCreate(app);
                } catch (Exception e) {
                  ... ...
                }
            }
    

    若传递的instrumentation不为空,则执行其onCreate,之前在bindAppliction里面调用传递参数是空,所以只是实例化了Application,这里在参数不为空,如果这个Application不是应用进程的第一个Application,那么会在这里实例化并调用onCreate 。

    Activity.attach

    可以看出,如果同一个进程运行多个应用的话,除了一个应用外,一个应用的第一个Activity会比Application先实例化,只是生命周期的执行时机在Application后面。Activity的创建过程是先反射创建其实例,然后作为参数创建其委托对象ContextImpl,然后attach这个对象,将ContextImpl作为自己的成员变量,很多功能会委托给这个对象实现,除此之外Activity.attach方法还会为创建PhoneWindow作为成员变量。

    callActivityOnCreate

    attach之后,来到mInstrumentation.callActivityOnCreate,这里会执行Activity的onCreate,activity.performStart,调用activity.onStart,mInstrumentation.callActivityOnRestoreInstanceState,调用Activity.onRestoreInstanceState,performLaunchActivity 方法返回之后,handleLaunchActivity继续走到ActivityThread.handleResumeActivity,调用Activity.onResume 。这些方法里面还夹杂Fragment的管理,这里先忽略。

    scheduleStopActivity

    至此,完成这个应用启动需要走的所有生命周期,而Launcher我们只分析到OnPause,一个完整的过程它是需要走到onStop才对的,我们看下在Launcher的ActivityThread调用ams的activityPaused里面,AMS除了通知Zygote孵化新进程外还做了什么,我们先回顾下创建应用进程的调用栈,:

    在这里插入图片描述

    Launcher在走完onPause生命周期后,就会通知AMS去启动新的Activity,而启动时发现对应的进程还没创建,所以这里先创建进程,这之后AMS就等着新启动的进程走到java层的attach方法来注册自己。

    我们看上面这个执行过程,在completePausedLocked方法里,还有另一个调用,看下面的调用栈:

    在这里插入图片描述

    往Handler里面发了一条消息,这个handler携带的消息会在system_server的一个Looper子线程里被处理,我们看其处理的调用栈:

    在这里插入图片描述

    这里就会去执行经过Binder和Handler中转,就会走到Launcher的的onStop生命周期了。

    回顾

    到这里大家可以回顾一下两个应用的的Activity生命周期是怎么走的,首先Launcher向AMS发消息要启动一个Activity,AMS发消息回来,让Launcher走到onPause,然后Launcher告诉AMS onPause已经调用,这个“通知”的过程中往system_server的一个Looper线程中发了条消息,这个消息收到后就会再回过来调用到Launcher的onStop,同时,还通过Process.start通知Zygote孵化出要启动的应用进程,应用进程启动后通过AMP.attachApplication注册自己的ApplicationThread到AMS,AMS回过来通过ApplicationThread执行了应用的bindApplication和scheduleLaunchActivity,前者完成Application对象实例化,Instrumentation初始化,ContentProvider的实例化和onCreate调用,Application的onCreate的调用,后者完成Activity的实例化,以及onCreate,onStart,onResume 连续三个生命周期的调用。这里可以看出两点:

  • Application的实例化是在ContentProvider之前的,但是Application的onCreate调用时机其实是在ContentProvider的onCreate之后的。
  • Launcher的onStop的调用其实和被启动的应用的Activity的生命周期是没有绝对的先后顺序的,但它的onPause肯定是要先被执行的(而在这之前还会通知WMS显示应用的startingWindow),其调用时机甚至比新应用进程的创建还早,AMS会等它被调用后才通知Zygote孵化新进程(其实也不绝对,想象如果onPause耗时太久,必然会影响新进程的启动了,这里AMS会有超时机制,超过500毫秒还没有通知AMS activityPaused,AMS就会不再等待,直接创建新进程)
  • 详细关注公众号:Android老皮
    还能解锁  《Android十大板块文档》 ,让学习更贴近未来实战。已形成PDF版

    内容如下:

    1.Android车载应用开发系统学习指南(附项目实战)
    2.Android Framework学习指南,助力成为系统级开发高手
    3.2023最新Android中高级面试题汇总+解析,告别零offer
    4.企业级Android音视频开发学习路线+项目实战(附源码)
    5.Android Jetpack从入门到精通,构建高质量UI界面
    6.Flutter技术解析与实战,跨平台首要之选
    7.Kotlin从入门到实战,全方面提升架构基础
    8.高级Android插件化与组件化(含实战教程和源码)
    9.Android 性能优化实战+360°全方面性能调优
    10.Android零基础入门到精通,高手进阶之路

    相关文章

    服务器端口转发,带你了解服务器端口转发
    服务器开放端口,服务器开放端口的步骤
    产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
    如何使用 WinGet 下载 Microsoft Store 应用
    百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
    百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

    发布评论