【Android 源码分析】Activity生命周期之onPause

news2024/12/23 1:25:08

忽然有一天,我想要做一件事:去代码中去验证那些曾经被“灌输”的理论。
                  
                  
                                           – 服装学院的IT男

本篇已收录于Activity短暂的一生系列
欢迎一起学习讨论Android应用开发或者WMS
V:WJB6995
Q:707409815

正文

Activity 生命周期是学习 Android 必定要掌握的知识点,但是刚入行的同学对于这个概念基本上是靠死记硬背,有一些实际工作经验的同学,在工作中通过实现业务需求或者解决一些BUG基本上是可以知道哪些生命周期对应用户操作的哪一步。

虽然触发生命周期的场景很多,当前只还是以在桌面启动应用来分析,但是完整的跟过这一流程的代码逻辑,就能加深对生命周期本质的理解,其他场景的生命周期切换也不是啥问题。

生命周期系列:

  • Activity生命周期之onPause

  • onCreate,onStart,onResume-1

  • onCreate,onStart,onResume-2

  • Activity生命周期之onStop-1

  • Activity生命周期之onStop-2

  • Activity生命周期之onDestory

本篇会介绍生命周期的执行顺序和 onPause 的执行逻辑

1. 生命周期介绍

回忆一下2个 Activity 的定义:

  • SourceActivity:执行 startActivity 方法的 Activity,也就是发起请求的Activity,当前就是 Launcher 的 Activity

  • TargetActivity:需要被启动的 Activity,当前就是“电话”应用在清单文件配置的 MainActivity

在 Activity.java 中,每个生个周期的执行都有对应的log打印,比如 onPause

# Activity
    // 默认为false,需要收到打开
    private static final boolean DEBUG_LIFECYCLE = true;

    protected void onPause() {
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onPause " + this);
        ......
    }

打开log开关后,操作一遍就获得到了下面的生命周期日志:
在这里插入图片描述
根据这里的日志打印就可以得出以下结论:

    1. 先执行 SourceActivity 的 onPause
    1. 然后依次执行 TargetActivity onCreate,onStart,onResume 三个生命周期
    1. 最后执行 SourceActivity 的 onStop
    1. 冷启动热启动的生命周期执行顺序都是一样的

如果没有条件编译AOSP的同学,搞个Activity在各自的生命周期加上log也能得到这样的一份log

根据之前【Activity启动流程】的知识和这份生命周期的log,可以得到下面这个图:

在这里插入图片描述
SystemService 会先触发 SourceActivity 的 onPause,然后才允许启动新的 TargetActivity 。(鲁迅曾说过:俗话说旧的不去新的不来)

SourceActivity 执行了 onPause 的时候,TargetActivity 还没起来,所以说 onPause 的时候,Activity也是可见的,只有知道到 onStop才不可见,因为 TargetActivity 已经显示了。

知道这几个生命周期的执行顺序其实就已经可以开始反向推到调用流程了,但是可以通过 events 日志,把流程具体化,完整流程对应的 events 日志如下:

在这里插入图片描述
只有分析流程的时候,按顺序像连线一样找到各个日志打印的地方,形成调用链,那整个生命周期的源码分析就完成了。

这里把 events 日志做了一些简化和加上了注释,如果以后遇到流程异常的,就可以和这份正常的日志对比一下,哪一步开始出问题了,然后去定位问题原因。

// SystemService端创建TargetActivity  (writeWmCreateActivity)
03-27 14:41:06.428 27889 28629 I wm_create_activity: [0,253598020,21,com.google.android.dialer/.extensions.GoogleDialtactsActivity,android.intent.action.MAIN,NULL,NULL,270532608]

// SystemService端触发SourceActivity的Pause (writeWmPauseActivity)
03-27 14:41:06.431 27889 28629 I wm_pause_activity: [0,51114540,com.android.launcher3/.uioverrides.QuickstepLauncher,userLeaving=true,pauseBackTasks]

// SourceActivity应用端将执行onPause (writeWmOnPausedCalled)
03-27 14:41:06.448 28606 28606 I wm_on_paused_called: [51114540,com.android.launcher3.uioverrides.QuickstepLauncher,performPause]

// SystemService端把SourceActivity添加进需要stop的集合 (writeWmAddToStopping)
03-27 14:41:06.459 27889 28630 I wm_add_to_stopping: [0,51114540,com.android.launcher3/.uioverrides.QuickstepLauncher,makeInvisible]

// SystemService端要真正触发TargetActivity启动 (writeWmRestartActivity)
03-27 14:41:06.487 27889 28630 I wm_restart_activity: [0,253598020,21,com.google.android.dialer/.extensions.GoogleDialtactsActivity]

// TargetActivity端将执行onCreate  (writeWmOnCreateCalled)
03-27 14:41:06.769  3401  3401 I wm_on_create_called: [253598020,com.google.android.dialer.extensions.GoogleDialtactsActivity,performCreate]

// TargetActivity端将执行onStart (writeWmOnStartCalled)
03-27 14:41:06.900  3401  3401 I wm_on_start_called: [253598020,com.google.android.dialer.extensions.GoogleDialtactsActivity,handleStartActivity]

// TargetActivity端将执行Resume (writeWmOnResumeCalled)
03-27 14:41:06.911  3401  3401 I wm_on_resume_called: [253598020,com.google.android.dialer.extensions.GoogleDialtactsActivity,RESUME_ACTIVITY]

// SystemService端触发SourceActivity的stop (writeWmStopActivity)
03-27 14:41:07.097 27889 30491 I wm_stop_activity: [0,51114540,com.android.launcher3/.uioverrides.QuickstepLauncher]

// SourceActivity应用端将执行onStop (writeWmStopActivity)
03-27 14:41:07.119 28606 28606 I wm_on_stop_called: [51114540,com.android.launcher3.uioverrides.QuickstepLauncher,STOP_ACTIVITY_ITEM]

1.1 生命周期事务

Activity各个生命周期的执行被封装成了一个事务,具体的映射关系如下:

LaunchActivityItem      onCreate
StartActivityItem       Start
ResumeActivityItem      onResume
PauseActivityItem       Pause
StopActivityItem        Stop
ActivityRelaunchItem    relaunch
ActivityResultItem      result

各个类被定义在 frameworks/base/core/java/android/app/servertransaction/ 路径下:

在这里插入图片描述
这些类都实现了 BaseClientRequest 接口,所以都有 preExecute ,execute ,postExecute 3个方法。
其实 execute 表示真正触发应用端执行对应的生命周期,而 preExecute,,postExecute 分别对应执行生命周期前后该做的事,这3个方法的执行循序如下:

preExecute -》execute -》postExecute

这些后续在代码中也能论证。

2. onPause

根据之前的分析知道 SourceActivity 是最先执行的,这个时候 TargetActivity 是还没有启动的。

pause流程对应的事务是 PauseActivityItem ,所以构建这个事务之前的调用逻辑就是 pause 流程在 SystemService 的处理,而 PauseActivityItem::execute 后的调用逻辑就是 pause 流程在应用端的处理。

目标明确,开始分析看代码。

2.1 SystemService 触发 pause 流程

构建 PauseActivityItem 的地方在 TaskFragment::schedulePauseActivity 方法中,在【Activity启动流程1】中知道在流程早起会执行下面这段调用链:

    ActivityTaskManagerService::startActivity
        ActivityTaskManagerService::startActivityAsUser
            ActivityTaskManagerService::startActivityAsUser
                ActivityStartController::obtainStarter
                    ActivityStarter::execute
                        ActivityStarter::executeRequest -- 构建 ActivityRecord --2.1 创建ActivityRecord
                            ActivityStarter::startActivityUnchecked
                                ActivityStarter::startActivityInner        -- 2.2 关键函数startActivityInner
                                    ActivityStarter::getOrCreateRootTask   -- 2.2.1 创建或者拿到Task
                                    ActivityStarter::setNewTask            -- 2.2.2 将task与activityRecord 绑定
                                    RootWindowContainer::resumeFocusedTasksTopActivities    --2.2.3 处理需要显示的Activity

RootWindowContainer::resumeFocusedTasksTopActivities 方法后续的逻辑如下:

    RootWindowContainer::resumeFocusedTasksTopActivities
        Task::resumeTopActivityUncheckedLocked
            Task::resumeTopActivityInnerLocked
                TaskFragment::resumeTopActivity 
                    TaskDisplayArea::pauseBackTasks  --   Pause SourceActivity 逻辑 (第一次执行)
                        WindowContainer::forAllLeafTask
                            TaskFragment::forAllLeafTaskFragments
                                TaskFragment::startPausing
                                    TaskFragment::startPausing
                                        TaskFragment::schedulePauseActivity --构建 PauseActivityItem,这里是触发SourceActivity的pause
                    ActivityTaskManagerService::startProcessAsync           -- 创建TargetActivity所在的进程 (第一次执行,且需要启动目标进程)

                    ActivityTaskSupervisor::startSpecificActivity           -- 启动TargetActivity(第二次执行,现在有个印象)

需要注意的是,上面的 RootWindowContainer::resumeFocusedTasksTopActivities 触发的逻辑是会执行2次的

第一次调用就是启动流程 startActivity 触发的,执行到 TaskFragment::resumeTopActivity 方法时,触发 SourceActivity 的 pause 流程和创建 TargetActivity 的进程。(应用内启动Activity肯定就不会触发进程创建了)

第二次触发是 SourceActivity 执行完 pause 后,就会触发 completePause 流程,这次执行到 TaskFragment::resumeTopActivity 方法时走的是触发启动 TargetActivity 流程。完整调用链如下:

    ActivityClientController::activityPaused
        ActivityRecord::activityPaused
            TaskFragment::completePause
                RootWindowContainer::resumeFocusedTasksTopActivities       --分支1  再次执行 resumeFocusedTasksTopActivities
                    RootWindowContainer::resumeFocusedTasksTopActivities
                        Task::resumeTopActivityUncheckedLocked
                            Task::resumeTopActivityInnerLocked
                                TaskFragment::resumeTopActivity
                                    ActivityTaskSupervisor::startSpecificActivity                           -- 启动TargetActivity
                RootWindowContainer::ensureActivitiesVisible              --分支2  确保有Activity显示流程

这里需要注意 completePause 流程再次执行 RootWindowContainer::resumeFocusedTasksTopActivities 方法时内部还会触发 TaskFragment::resumeTopActivity 方法,而这一次触发的是启动 TargetActivity 的流程。

同一个方法因为执行时机不同,走不同的逻辑,这种情况在分析源码的时候非常让人头疼,上面做了一些说明并且提供了调用链。

本篇其实需要注意的只有第一次执行的逻辑处理,因为第二次是 completePause 流程了,触发的是TargetActivity 流程也就是 TargetActivity 的onCreate,onStart,onResume 三个生命周期执行,是下一篇的触发逻辑,当前有个印象即可。

其他的地方在【Activity启动流程】系列都分析过来,目前只关注 pause 逻辑即可,看一下 TaskFragment::resumeTopActivity 方法的代码。

2.1.1 TaskFragment::resumeTopActivity 方法

    # TaskFragment
        final boolean resumeTopActivity(ActivityRecord prev, ActivityOptions options,
                boolean deferPause) {
                    // 这里的next返回下一个需要显示的Activity
                    ActivityRecord next = topRunningActivity(true /* focusableOnly */);
                    ...... // 如果跳过的这些逻辑都没执行return,则开始执行resume流程,如果被return了也会打印日志。    
            
                    // 打印日志,需要显示哪个Activity(也就是SourceActivity)
                    if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next);
                    ......
                    // 重点* 1. 第一次执行走这,执行SourceActivity的pause流程
                    boolean pausing = !deferPause && taskDisplayArea.pauseBackTasks(next);
                    ......
                    if (pausing) {
                        ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivity: Skip resume: need to"+ " start pausing");
                        if (next.attachedToProcess()) {
                            ......
                        } else if (!next.isProcessRunning()) {
                            // 进程没有运行,则触发异步创建进程。 当前逻辑肯定是执行
                            final boolean isTop = this == taskDisplayArea.getFocusedRootTask();
                            mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop,
                                isTop ? HostingRecord.HOSTING_TYPE_NEXT_TOP_ACTIVITY
                                        : HostingRecord.HOSTING_TYPE_NEXT_ACTIVITY);
                        }
                        ......
                        // 注意,这里会return,所以第一次执行到这就结束了。
                        return true;
                    }
                    ......
                    ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Restarting %s", next);
                    // 重点*2. 第二次执行的时候走这,SourceActivity已经执行完pause流程了,所以走这启动Activity走这
                    mTaskSupervisor.startSpecificActivity(next, true, true); 
                }

这个方法是极其复杂的, 但是基于前面的铺垫后再看这个方法,我觉得应该目标明确了,由于当前是分析的是 onPause流程,所以只看第一次执行的调用链即可,也就是 pauseBackTasks 方法。

TaskDisplayArea::pauseBackTasks 方法的逻辑从前面的调用链知道会执行 TaskFragment::schedulePauseActivity 方法,这中间的调用逻辑在【Activity启动流程-2】中有详细分析,当前直接看 schedulePauseActivity 方法。


    # TaskFragment

        void schedulePauseActivity(ActivityRecord prev, boolean userLeaving,
                boolean pauseImmediately, String reason) {
            // Proto日志
            ProtoLog.v(WM_DEBUG_STATES, "Enqueueing pending pause: %s", prev);
            try {
                // 输出events 日志 wm_pause_activity
                EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev),
                        prev.shortComponentName, "userLeaving=" + userLeaving, reason);
                // 重点* 构建并执行PauseActivityItem
                mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
                        prev.token, PauseActivityItem.obtain(prev.finishing, userLeaving,
                                prev.configChangeFlags, pauseImmediately));
            } catch (Exception e) {
                ......
            }
        }
    1. 打印第一个 events 日志:wm_pause_activity
    1. 构建执行 PauseActivityItem 事务

SystemService 触发 pause 的逻辑就分析完了,PauseActivityItem 是承上启下的关键线索,看看这个事务做了些什么。

2.2 PauseActivityItem

    # PauseActivityItem

        @Override
        public void execute(ClientTransactionHandler client, ActivityClientRecord r,
                PendingTransactionActions pendingActions) {
                // trace
                Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
                //  触发应用进程pause
                client.handlePauseActivity(r, mFinished, mUserLeaving, mConfigChanges, pendingActions,
                        "PAUSE_ACTIVITY_ITEM");
                Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
        }

        @Override
        public int getTargetState() {
            return ON_PAUSE;
        }

        @Override
        public void postExecute(ClientTransactionHandler client, IBinder token,
                PendingTransactionActions pendingActions) {
                if (mDontReport) {
                    return;
                }
                // 自己加的Trace
                Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityPaused");
                // TODO(lifecycler): Use interface callback instead of actual implementation.
                // 触发 completePause 流程
                ActivityClient.getInstance().activityPaused(token);
                Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
        }
    1. 先执行 execute ,最终触发应用端 Activity 的 onPause
    1. 然后执行 postExecute ,这里的逻辑是由 SystemService 执行 completePause 流程

这2个发生是同步触发,但是具体触发逻辑所在的进程都不一样,所以肯定是异步执行的,没有强绑定关系, 换句话说就是 应用端的 Activity 是不是真的顺利执行完了 onPause,和 completePause 流程没有必然关系。

这点很重要,后面看 onStop 流程的时候还会提到。

activityPaused 触发的后续逻辑就是 2.1 小节提到的第二次执行 TaskFragment::resumeTopActivity 方法来启动 Activity 的触发点。

当然本篇还是看 pause 逻辑,所以直接看 execute 方法触发的应用端是如何处理的。

2.3 应用端执行pause

应用端调用链如下:

ActivityThread::handlePauseActivity
    ActivityThread::performPauseActivity
        ActivityThread::performPauseActivityIfNeeded
            InstrumentationcallActivityOnPause
                Activity::performPause
                    Activity::onPause    -- onPause
        ActivityClientRecord::setState   -- 设置状态ON_PAUSE(4)

代码流程也很简单,看一下。

    # ActivityThread

        @Override
        public void handlePauseActivity(ActivityClientRecord r, boolean finished, boolean userLeaving,
                int configChanges, PendingTransactionActions pendingActions, String reason) {
            ......
            r.activity.mConfigChangeFlags |= configChanges;
            performPauseActivity(r, finished, reason, pendingActions);
            ......
        }


       private Bundle performPauseActivity(ActivityClientRecord r, boolean finished, String reason,
                PendingTransactionActions pendingActions) {
                ......
                // Pre-Honeycomb apps always save their state before pausing
                final boolean shouldSaveState = !r.activity.mFinished && r.isPreHoneycomb();
                if (shouldSaveState) {
                    // 安卓3之前的版本是在onPause执行执行OnSaveInstanceState的
                    callActivityOnSaveInstanceState(r);
                }
                // onPause 逻辑
                performPauseActivityIfNeeded(r, reason);
                ......
       }

稍微提到了一下 OnSaveInstanceState 的调用时机,Honeycomb 是安卓3, 现在基本上没有这种手机了,了解一下即可,继续看主流程。

    # ActivityThread
        Instrumentation mInstrumentation;

        private void performPauseActivityIfNeeded(ActivityClientRecord r, String reason) {
            // 如果已经 paused 就不许要处理了
            if (r.paused) {
                // You are already paused silly...
                return;
            }
            try {
                r.activity.mCalled = false;
                // 主流程
                mInstrumentation.callActivityOnPause(r.activity);
                if (!r.activity.mCalled) {
                    throw new SuperNotCalledException("Activity " + safeToComponentShortString(r.intent)
                            + " did not call through to super.onPause()");
                }
            } catch ......

            // 需要留意一下 这里的状态是生命周期,不是ActivityRecord的那个状态 
            r.setState(ON_PAUSE);
        }

又看到了 Instrumentation

    # Instrumentation

        public void callActivityOnPause(Activity activity) {
            activity.performPause();
        }

<!---->

    # Activity 
        final void performPause() {
            // 1. Trace begin
            if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
                Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "performPause:"
                        + mComponent.getClassName());
            }
            dispatchActivityPrePaused();
            mDoReportFullyDrawn = false;
            // 2. Fragments处理
            mFragments.dispatchPause();
            mCalled = false;
            // 3. 重点* onPause
            onPause();
            // 4. events日志  wm_on_paused_called
            EventLogTags.writeWmOnPausedCalled(mIdent, getComponentName().getClassName(),
                    "performPause");
            mResumed = false;
            ......
            // Trace end
            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
        }

到这里 onPause 流程就分析完了, 这里有几个需要注意的点

    1. 有Trace
    1. 对Fragments处理
    1. 最重要的触发了 Activity 的 onPause
    1. 打印日志 wm_on_paused_called ,表示应用端已经pause了

到这里 SourceActivity 的 Pause 流程已经完全结束了。

3 ActivityClientRecord 是什么

在 ActivityThread::performPauseActivityIfNeeded 中看到在触发 onPause 执行后还会调用 ActivityClientRecord::setState 方法传递了一个 ON_PAUSE 进去。

这句代码大概意思猜着就是设置一个 ON_PAUSE 的状态保存起来。

可是 SystemService 端有个 ActivityRecord 来记录 Activity的一些信息,那这个 ActivityClientRecord 又是什么呢?

从命名上来看,好像和 ActivityRecord 类似,是 Client(客户端)这边记录 Activity 的一个类,实际上也确实如此,ActivityClientRecord 内部也保存了很多与 Activity 启动和运行相关的各种参数,如Intent、token、binder引用等。以后遇到再说,不过目前我们关注生命周期相关的,先看看 setState 这个方法。


    # ActivityThread$ActivityClientRecord
            // 是否paused
            @UnsupportedAppUsage
            boolean paused;

            // 是否stoped
            @UnsupportedAppUsage
            boolean stopped;

            // 生命周期状态
            @LifecycleState
            private int mLifecycleState = PRE_ON_CREATE;

            /** Update the current lifecycle state for internal bookkeeping. */
            // 更新内部保存的生命周期状态
            public void setState(@LifecycleState int newLifecycleState) {
                mLifecycleState = newLifecycleState;
                switch (mLifecycleState) {
                    case ON_CREATE:
                        // 刚刚创建,不可见,不可交互
                        paused = true; 
                        stopped = true; 
                        break;
                    case ON_START:
                        // 还没完全进入前台,但已经可见,不可交互
                        paused = true; 
                        stopped = false; 
                        break;
                    case ON_RESUME:
                        // 可见,可交互
                        paused = false;
                        stopped = false; 
                        break;
                    case ON_PAUSE:
                        // 未被完全遮挡,可见,不可交互
                        paused = true; 
                        stopped = false; 
                        break;
                    case ON_STOP:
                        // 被完全遮挡,所以不可见,也不可交互
                        paused = true;  
                        stopped = true; 
                        break;
                }
            }

这段代码有3个变量:

    1. paused: 表示当前Activity 是否处于暂停(pause)状态,也就是能不能和用户交互
    1. stopped : 表示当前Activity是否处于 停止(stop)状态,也就是能不能被用户可见
    1. mLifecycleState :这是一个被LifecycleState注解的变量,说明取值只能是内部定义的几个生命周期

关于pause和stop的区别可能有些小伙伴还很迷糊,这里表达一下我的理解:
onPause和onStop都是不能和用户交互的,但是 onPause 的时候,Activity 还是可见的,比如出现一个dialog主题的Activity,这个时候下面的 Activity 就是pause,但不是stop,因为它还能被用户看见。

从log来看,SourceActivity 的onPause是最先执行的,但是onStop却要等 TargetActivity 执行完 onResume 再执行

抛开代码从实际情况来说,SourceActivity 要不可见,就只有等 TargetActivity 完全显示(onResume)的时候才可以算 onStop 了

@LifecycleState 注解是定义在 ActivityLifecycleItem下的

    # ActivityLifecycleItem
        @Retention(RetentionPolicy.SOURCE)
        public @interface LifecycleState{}
        public static final int UNDEFINED = -1;
        public static final int PRE_ON_CREATE = 0;
        public static final int ON_CREATE = 1;
        public static final int ON_START = 2;
        public static final int ON_RESUME = 3;
        public static final int ON_PAUSE = 4;
        public static final int ON_STOP = 5;
        public static final int ON_DESTROY = 6;
        public static final int ON_RESTART = 7;

可以看到 从 1-7 刚好是和 7个生命周期对应的,这里需要注意对应的几个int值,后面的代码还要用到。

当前 pause 流程传递了一个 ON_PAUSE 进去 那当前 mLifecycleState 的值就是 ON_PAUSE(4)。

4. 总结

本篇首先明确了启动 Activity 生命周期的先后执行顺序,然后介绍了完整流程的 events 日志。

然后知道了 startActivity 流程最开始会执行到 TaskFragment::resumeTopActivity 方法,在这里会触发 SourceActivity 的 pause 流程,同时还会创建 TargetActivity 所在的进程(有必要的话)
我对关键方法加上了一个 Trace 后,当前桌面冷启动应用场景得到的Trace如下:

在这里插入图片描述

    1. 可以看到 TaskFragment::resumeTopActivity 执行了2次,上图是第一次
    1. 执行进程在 system_service
    1. 执行了 pauseBackTasks 流程,也就是 SourceActivity 的 pause
    1. 触发了TargetActivity 所在的进程创建

pauseBackTasks 方法后面会执行 TaskFragment::schedulePauseActivity 方法,在这个方法中有2个点:

    1. 打印日志:wm_pause_activity
    1. 构建执行 PauseActivityItem

而 PauseActivityItem 也做了2件事:

    1. 先执行 execute ,最终触发应用端 Activity 的 onPause
    1. 然后执行 postExecute ,这里的逻辑是由 SystemService 执行 completePause 流程。

本篇关心的是 execute 方法除非的逻辑,在应用段执行到 onPause 的逻辑,打印了 wm_on_paused_called 日志,流程也就分析完了。

最后再补充一下 postExecute 方法触在这里插入图片描述

    1. 执行进程还是在 system_service
    1. 这里的 resumeTopActivity 上面是 activityPaused,也就是我在 PauseActivityItem::postExecute 加是 trace
    1. 虽然还会执行 pauseBackTasks 但是下面没有构建 pause 事务的逻辑了
    1. 这一次执行还会触发prepareAppTransition方法
    1. 最终要的是要创建 TargetActivity 了,下一篇是基于这个基础

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2183537.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux操作常用问题

目录 Ubuntu操作问题vi编辑方向键键盘乱码回退键不能使用的问题解决问题的方法 Ubuntu操作问题 vi编辑方向键键盘乱码回退键不能使用的问题 编辑/etc/systemd/resolved.conf文件来修改DNS&#xff0c;结果编辑时键盘乱码&#xff0c;按下方向键会出现ABCD&#xff0c;且回退键…

解决json格式转换被特殊字符截断问题

SyntaxError&#xff1a;Unexpected end of JSON input 当我们使用navigateTo跳转传参的时候&#xff0c;在小程序中需要先转换为json字符串的格式化&#xff0c;但是如果我们传递的参数中有特殊字符的&#xff1f;/&amp的话&#xff0c;可能导致字符串被截断&#xff0c;此…

手搓游戏 —— 生成式 AI 助手 Amazon Q Developer 初体验

文章目录 一、Amazon Q介绍二、实验环境准备2.1 下载项目安装包2.2 验证 Python 环境2.3 安装Amazon Q扩展2.4 授权Builder ID 三、Amazon Q 快速理解main.py四、Amazon Q快速梳理控制器逻辑五、启动像素沙盒开放世界程序六、在 update() 中实现传送功能七、定位并修复代码漏洞…

【无人机设计与技术】自抗扰控制(ADRC)的建模与仿真研究

摘要 本文针对四旋翼无人机姿态控制系统进行了基于自抗扰控制(ADRC)的建模与仿真研究。通过MATLAB/Simulink仿真平台&#xff0c;实现了无人机的姿态控制模型&#xff0c;并采用自抗扰控制器(ADRC)对无人机的姿态进行控制。本文详细介绍了自抗扰控制器的设计方法和应用&#x…

机器学习模型评估

前言 承接上篇讲述了机器学习有哪些常见的模型算法&#xff0c;以及适用的场景&#xff0c;本篇将继续讲述如何评估模型。模型评估的目的是选出泛化能力强的模型。泛化能力强表示模型能很好地适用于未知的样本&#xff0c;模型的错误率低、精度高。本文将从评估方法和评估指标…

【开源鸿蒙】OpenHarmony 5.0.0 发布了,速来下载最新代码

【开源鸿蒙】OpenHarmony 5.0.0 发布了&#xff0c;速来下载最新代码 一、写在前面二、准备命令工具三、配置用户信息四、下载OpenHarmony源码4.1 使用ssh协议下载&#xff08;推荐&#xff09;4.2 使用https协议下载 五、下载编译工具链六、参考链接 今天是9月30号&#xff0c…

20道面试题001

常考语法就是指针&#xff0c;指针与数组、指针与字符串、指针与结构体、指针与函数之间的关系与使用&#xff0c; 以上课为准&#xff0c;辅助《深度理解C指针》这本书。 1. 指针与数组 定义: 数组名在表达式中通常被视为指向数组首元素的指针。 访问元素: 可以通过指针访问数…

计算机网络:计算机网络概述:网络、互联网与因特网的区别

文章目录 网络、互联网与因特网的区别网络分类 互联网因特网基于 ISP 的多层次结构的互连网络因特网的标准化工作因特网管理机构因特网的组成 网络、互联网与因特网的区别 若干节点和链路互连形成网络&#xff0c;若干网络通过路由器互连形成互联网 互联网是全球范围内的网络…

PWM驱动LED呼吸灯

背景知识&#xff1a;TIM输出比较-CSDN博客 stm32f10x_tim.h函数 // *** OC是Output Compare输出比较函数 void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct); void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct); void TI…

给Windows系统设置代理的操作方法

一、什么是代理 网络代理是一种特殊的网络服务&#xff0c;允许一个网络终端通过这个服务与另一个网络终端进行非直接的连接&#xff0c;而提供代理服务的电脑系统或其它类型的网络终端被称为代理服务器。 代理服务器是网络信息的中转站&#xff0c;代理服务器就像是一个很大的…

56. QTreeWidget的基本使用

1. 说明 在软件开发中会遇到将数据信息制作成一种树目录的形式进行展示,那么此时就可以借助QT提供的QTreeWidget控件来实现这种需求,本篇博客会做一个案例简要说明这个控件的基本使用方法,博客中代码能够实现的功能是将此项目代码所在文件夹中的内容展示出来,如下图所示:…

模式识别编程实践1:身高和/或体重数据进行性别分类

&#x1f31e;欢迎莅临我的个人主页&#x1f448;&#x1f3fb;这里是我专注于深度学习领域、用心分享知识精粹与智慧火花的独特角落&#xff01;&#x1f349; &#x1f308;如果大家喜欢文章&#xff0c;欢迎&#xff1a;关注&#x1f377;点赞&#x1f44d;&#x1f3fb;评论…

回溯大总结

目录 0、基础什么是回溯&#xff1f;回溯法解决的问题回溯模板 1、组合问题77. 组合216.组合总和III17. 电话号码的字母组合39. 组合总和&#xff1a;40.组合总和II 0、基础 什么是回溯&#xff1f; 回溯是一种穷举的搜索算法&#xff0c;并不是一个高效的算法&#xff0c;当…

高并发内存池(五):ThreadCache、CentralCache和PageCache的内存回收机制、阶段性代码展示和释放内存过程的调试

目录 ThreadCache的内存回收机制 补充内容1 补充内容2 补充内容3 补充内容4 ListTooLong函数的实现 CentralCache的内存回收机制 MapObjectToSpan函数的实现 ReleaseListToSpans函数的实现 PageCache的内存回收机制 补充内容1 补充内容2 ReleaseSpanToPageCache函…

【Spine】引入PhotoshopToSpine脚本

引入 右键Photoshop图标&#xff0c;选择属性 打开文件所在位置 找到目录下的\Presets\Scripts文件夹。 找到Spine目录下的\scripts\photoshop文件夹下的PhotoshopToSpine.jsx 复制它&#xff0c;丢到Photoshop刚才找的那个目录下。 使用 打开.psd文件&#xff0c;检查不要…

二叉树:总结篇!【需要掌握的二叉树技能都在这里啦】

文章目录 前言二叉树理论基础二叉树理论基础二叉树的遍历方式深度优先遍历广度优先遍历 N叉树的遍历方式求二叉树的属性二叉树&#xff1a;是否对称二叉树&#xff1a;求最大深度二叉树&#xff1a;求最小深度二叉树&#xff1a;求有多少个节点二叉树&#xff1a;是否平衡二叉树…

外贸财务软件精选,提升管理效率与精准度

ZohoBooks、QuickBooks等六款会计软件各具特色&#xff0c;支持多币种、国际化等功能&#xff0c;适合不同规模外贸企业。其中&#xff0c;ZohoBooks功能全面&#xff0c;QuickBooks操作简便&#xff0c;SageIntacct适合复杂业务&#xff0c;用友U8和金蝶K/3面向中大型企业&…

CommandLineRunner 和 ApplicationRunner

CommandLineRunner 和 ApplicationRunner 背景&#xff1a; 项目启动之前&#xff0c;预先加载数据。比如&#xff0c;权限容器、特殊用户数据等。通常我们可以使用监听器、事件来操作。但是&#xff0c;springboot提供了一个简单的方式来实现此类需求&#xff0c;即&#xf…

《Linux从小白到高手》理论篇(九):Linux的资源监控管理

本篇介绍Linux的资源监控管理。 1、CPU 资源管理 进程调度&#xff1a; Linux 采用公平的进程调度算法&#xff0c;确保每个进程都能获得合理的 CPU 时间。调度算法会根据进程的优先级、等待时间等因素来决定哪个进程获得 CPU 使用权。 可以通过调整进程的优先级来影响其获得…

C++继承实例讲解

C类继承的基本概念 base class&#xff0c;基类、父类 derived class&#xff0c;派生类、子类 C中的类可以扩展&#xff0c;创建保留基类特征的新类&#xff0c;这个过程称之为继承。类继承也可以描述为&#xff1a;派生类继承基类的成员&#xff0c;并在其上添加自己的成员…