Android进阶 四大组件的工作过程(一):Activity的工作过程

这篇具有很好参考价值的文章主要介绍了Android进阶 四大组件的工作过程(一):Activity的工作过程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Android进阶 四大组件的工作过程(一):Activity的工作过程

Android进阶 四大组件的工作过程(一):Activity的工作过程

导语

本系列文章主要是来介绍Android中四大组件的工作过程的,参照书籍为Android进阶解密,主要还是会涉及到源码的阅读。关于源码,大家可以到Android Code Search上查看,网址放在这里了:Android Code Search。除此之外,最好还需要掌握一些Android系统启动过程的知识:

  1. Android系统的启动流程(一):进入Zygote进程的初始化
  2. Android系统的启动流程(二):SystemServer处理过程
  3. Android系统的启动过程(三):Launcher启动过程
  4. Android应用程序进程的启动过程

本篇文章,主要就是来介绍Activity的工作工程的,这里以启动根Activity为例,查看Activity是如何通过系统启动的。这里我们将其分为三个部分来分析,在这之前还是需要介绍一些基础的知识。

基础知识

  1. Launcher是Android系统启动后启动的第一个App,实际上就是手机桌面,它本质上也是一个Activity。我们就是通过这个Launcher来启动其他的App的。
  2. AMS(ActivityManagerService)是属于系统服务中的核心服务,主要就是用来管理应用程序进程的创建等任务的,我们的Activity的启动也会涉及到这个服务。
  3. Activity组件启动之前需要AMS委托Zygote进程来创建出应用程序的进程。有了进程之后才能启动Activity。

Launcher请求AMS(实际上是ATMS)过程

显然我们打开一个应用程序是通过桌面点击图标开始的,那我们启动一个跟Activity显然也是通过Launcher开始的。当我们点击某个应用程序的图标时,就会调用Launcher的startActivitySafely方法,而这个方法又会调用超类的startActivitySafely方法,我们直接看超类的(ActivityContext)方法:

default boolean startActivitySafely(
            View v, Intent intent, @Nullable ItemInfo item) {

        Context context = (Context) this;//1----1
        if (isAppBlockedForSafeMode() && !PackageManagerHelper.isSystemApp(context, intent)) {
            Toast.makeText(context, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
            return false;
        }

        Bundle optsBundle = (v != null) ? getActivityLaunchOptions(v, item).toBundle() : null;//2----2
        UserHandle user = item == null ? null : item.user;

        // Prepare intent
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//3----3
        if (v != null) {
            intent.setSourceBounds(Utilities.getViewBounds(v));
        }
        try {
            boolean isShortcut = (item instanceof WorkspaceItemInfo)
                    && (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
                    || item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT)
                    && !((WorkspaceItemInfo) item).isPromise();
            if (isShortcut) {
                // Shortcuts need some special checks due to legacy reasons.
                startShortcutIntentSafely(intent, optsBundle, item);
            } else if (user == null || user.equals(Process.myUserHandle())) {
                // Could be launching some bookkeeping activity
                context.startActivity(intent, optsBundle);//4----4
            } else {
                context.getSystemService(LauncherApps.class).startMainActivity(
                        intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
            }
            if (item != null) {
                InstanceId instanceId = new InstanceIdSequence().newInstanceId();
                logAppLaunch(getStatsLogManager(), item, instanceId);
            }
            return true;
        } catch (NullPointerException | ActivityNotFoundException | SecurityException e) {
            Toast.makeText(context, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
            Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
        }
        return false;
    }

我们分析一下这个方法,首先在注释一处它会将context对象设置为自身,这个context将会在后面使用到。接着再注释二处它获得了Activity启动的一些参数。在注释三处,它设置Intent的标志(Intent.FLAG_ACTIVITY_NEW_TASK),表示将在新的任务中启动Activity。

接着我们可以在注释四处发现有多处分支,具体来说,这里会根据情况进行启动Activity的操作。如果要启动的是一个快捷方式(Shortcut),则调用startShortcutIntentSafely方法来安全地启动快捷方式。否则,根据用户是否为当前用户来决定是调用startActivity方法还是通过LauncherApps来启动MainActivity。

这两种方式的区别在于:

  1. 使用context.startActivity(intent, optsBundle)来启动Activity是直接通过Context的方法启动,不涉及其他Launcher应用的介入。这种方式适用于启动当前应用的内部Activity,或者启动非Launcher应用的Activity。
  2. 使用LauncherApps.startMainActivity()方法启动MainActivity是通过系统的Launcher应用来启动目标Activity。这种方式通常用于启动其他应用的MainActivity,可以触发Launcher应用的一些额外处理逻辑,例如应用图标的动画、桌面的切换效果等。它还允许指定不同的用户(UserHandle)来启动Activity。

这里我们就进入注释四处的分支来启动了,这里将Intent和启动参数传入开始启动。这个方法如果继续点击去的话会跳到Context中,是个空方法,具体实现是在Activity类中,我们进入Activity中查看:

    public void startActivity(Intent intent, @Nullable Bundle options) {
        getAutofillClientController().onStartActivity(intent, mIntent);
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);
        }
    }

可以看到这个方法本质上是调用到startActivityForResult方法,第二个参数设置为-1表示Launcher不需要知道Activity启动的结果。接下来看startActivityForResult方法:

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            if (ar != null) {
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
            if (requestCode >= 0) {
                // If this start is requesting a result, we can avoid making
                // the activity visible until the result is received.  Setting
                // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
                // activity hidden during this time, to avoid flickering.
                // This can only be done when a result is requested because
                // that guarantees we will get information back when the
                // activity is finished, no matter what happens to it.
                mStartedActivity = true;
            }

            cancelInputsAndStartExitTransition(options);
            // TODO Consider clearing/flushing other event sources and events for child windows.
        } else {
            if (options != null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                // Note we want to go through this method for compatibility with
                // existing applications that may have overridden it.
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
    }

我们来看判断的第一个分支,mParent表示父Activity,由于当前启动的就是根Activity,所以mParent==null成立,会进入到这个分支里面来。很明显,接下来会通过Instrumentation的execStartActivity方法来继续启动Activity。这个Instrumentation类是Android框架提供的一个重要类,用于监测和控制应用程序的运行。它允许开发者在应用程序的各个生命周期阶段插入自定义的代码逻辑,以实现一些特定的功能,例如性能监测、代码覆盖率分析、UI自动化测试等。

接下来继续看execStartActivity方法:

    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        Uri referrer = target != null ? target.onProvideReferrer() : null;
		.......
        try {
            intent.migrateExtraStreamToClipData(who);
            intent.prepareToLeaveProcess(who);
            int result = ActivityTaskManager.getService().startActivity(whoThread,
                    who.getOpPackageName(), who.getAttributionTag(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()), token,
                    target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }

我们主要看后面的部分,这一段比较重要。这一段最主要的就是调用到了ActivityTaskManager的getService,然后通过这个Service来启动Activity,至于这个Service是什么,我们可以看一看这个getService方法:

    public static IActivityTaskManager getService() {
        return IActivityTaskManagerSingleton.get();
    }

    @UnsupportedAppUsage(trackingBug = 129726065)
    private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
            new Singleton<IActivityTaskManager>() {
                @Override
                protected IActivityTaskManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
                    return IActivityTaskManager.Stub.asInterface(b);
                }
            };

很显然这是一个AIDL的调用,获取到的是ActivityTaskManagerService的远程代理调用,而ActivityTaskManagerService是是 Android 系统中的一个重要组件,用于管理应用程序的活动(Activity)和任务(Task)。它是 Android 系统中的系统服务之一,负责跟踪和管理活动的生命周期、任务的堆栈以及任务切换等操作。我们之前提到的ActivityManagerService也会依赖到ActivityTaskService。

所以说这里最终会调用到ActivityTaskManagerService的startActivity方法:

    public final int startActivity(IApplicationThread caller, String callingPackage,
            String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
            String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
            Bundle bOptions) {
        return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
                resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,
                UserHandle.getCallingUserId());
    }

那么其实到这里Launcher的启动请求已经进入到了ActivityTaskManagerService中了,我们接下来看第二部分,也就是从ATMS开始。

AMS(ATMS)到ApplicationThread的调用过程

上面说到到这里请求已经传递到了ActivityTaskManagerService中,具体还是需要ActivityTaskManagerService来启动。调用其startActivity方法后就会继续跳转,调用它的startActivityAsUser方法,我们来看这个startActivityAsUser方法:

private int startActivityAsUser(IApplicationThread caller, String callingPackage,
            @Nullable String callingFeatureId, Intent intent, String resolvedType,
            IBinder resultTo, String resultWho, int requestCode, int startFlags,
            ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
        assertPackageMatchesCallingUid(callingPackage);
        enforceNotIsolatedCaller("startActivityAsUser");
        if (Process.isSdkSandboxUid(Binder.getCallingUid())) {
            SdkSandboxManagerLocal sdkSandboxManagerLocal = LocalManagerRegistry.getManager(
                    SdkSandboxManagerLocal.class);
            if (sdkSandboxManagerLocal == null) {
                throw new IllegalStateException("SdkSandboxManagerLocal not found when starting"
                        + " an activity from an SDK sandbox uid.");
            }
            sdkSandboxManagerLocal.enforceAllowedToStartActivity(intent);
        }

        userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
                Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");

        // TODO: Switch to user app stacks here.
        return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
                .setCaller(caller)
                .setCallingPackage(callingPackage)
                .setCallingFeatureId(callingFeatureId)
                .setResolvedType(resolvedType)
                .setResultTo(resultTo)
                .setResultWho(resultWho)
                .setRequestCode(requestCode)
                .setStartFlags(startFlags)
                .setProfilerInfo(profilerInfo)
                .setActivityOptions(bOptions)
                .setUserId(userId)
                .execute();

    }

这个方法到最后一句return语句之前都是在检查相关的权限,判断是否有启动Activity的权限;最后一句则是继续推进启动Activity,可以看到它设置了许多启动的参数,最后调用execute方法执行了命令。具体来说,就是先通过ActivityStarterController获得一个ActivityStarter,从名字就可以看出来ActivityStarter是用来启动Activity的,所以接下来进入到ActivityStarter的execute方法中:

int execute() {
        try {
            if (mRequest.intent != null && mRequest.intent.hasFileDescriptors()) {
                throw new IllegalArgumentException("File descriptors passed in Intent");
            }

            final LaunchingState launchingState;
            synchronized (mService.mGlobalLock) {
                final ActivityRecord caller = ActivityRecord.forTokenLocked(mRequest.resultTo);//1-----1
                final int callingUid = mRequest.realCallingUid == Request.DEFAULT_REAL_CALLING_UID
                        ?  Binder.getCallingUid() : mRequest.realCallingUid;
                launchingState = mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(
                        mRequest.intent, caller, callingUid);
            }

            if (mRequest.activityInfo == null) {
                mRequest.resolveActivity(mSupervisor); //2-----2
            }
			.........

            int res;
            synchronized (mService.mGlobalLock) {
                final boolean globalConfigWillChange = mRequest.globalConfig != null
                        && mService.getGlobalConfiguration().diff(mRequest.globalConfig) != 0;
                final Task rootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
                if (rootTask != null) {
                    rootTask.mConfigWillChange = globalConfigWillChange;
                }
                ProtoLog.v(WM_DEBUG_CONFIGURATION, "Starting activity when config "
                        + "will change = %b", globalConfigWillChange);

                final long origId = Binder.clearCallingIdentity();

                res = resolveToHeavyWeightSwitcherIfNeeded();
                if (res != START_SUCCESS) {
                    return res;
                }
                res = executeRequest(mRequest);//3-----3

              	........
    }

我们从上往下继续看,注释一处获取到了ActivityRecord类的对象,这个类是用来描述Activity信息的,也就是我们要启动的Activity的信息,注释二处将会解析Activity的信息,接着在注释三处执行请求,其实主要还是看注释三处,我们来看这个executeRequest方法:

    private int executeRequest(Request request) {
        if (TextUtils.isEmpty(request.reason)) {
            throw new IllegalArgumentException("Need to specify a reason.");
        }
        mLastStartReason = request.reason;
        mLastStartActivityTimeMs = System.currentTimeMillis();
        mLastStartActivityRecord = null;

        final IApplicationThread caller = request.caller; //1---------1
        Intent intent = request.intent;
        NeededUriGrants intentGrants = request.intentGrants;
        String resolvedType = request.resolvedType;
        ActivityInfo aInfo = request.activityInfo;
        ResolveInfo rInfo = request.resolveInfo;
       ..........

        int err = ActivityManager.START_SUCCESS;
        final Bundle verificationBundle =
                options != null ? options.popAppVerificationBundle() : null;

        WindowProcessController callerApp = null;
        if (caller != null) {   //2---------2
            callerApp = mService.getProcessController(caller);
            if (callerApp != null) {
                callingPid = callerApp.getPid();
                callingUid = callerApp.mInfo.uid;
            } else {
                Slog.w(TAG, "Unable to find app for caller " + caller + " (pid=" + callingPid
                        + ") when starting: " + intent.toString());
                err = START_PERMISSION_DENIED;
            }
        }

     	.........

        final ActivityRecord r = new ActivityRecord.Builder(mService)//3---------3
                .setCaller(callerApp)
                .setLaunchedFromPid(callingPid)
                .setLaunchedFromUid(callingUid)
                .setLaunchedFromPackage(callingPackage)
                .setLaunchedFromFeature(callingFeatureId)
                .setIntent(intent)
                .setResolvedType(resolvedType)
                .setActivityInfo(aInfo)
                .setConfiguration(mService.getGlobalConfiguration())
                .setResultTo(resultRecord)
                .setResultWho(resultWho)
                .setRequestCode(requestCode)
                .setComponentSpecified(request.componentSpecified)
                .setRootVoiceInteraction(voiceSession != null)
                .setActivityOptions(checkedOptions)
                .setSourceRecord(sourceRecord)
                .build();

        mLastStartActivityRecord = r;

        if (r.appTimeTracker == null && sourceRecord != null) {
            r.appTimeTracker = sourceRecord.appTimeTracker;
        }

        WindowProcessController homeProcess = mService.mHomeProcess;
        boolean isHomeProcess = homeProcess != null
                && aInfo.applicationInfo.uid == homeProcess.mUid;
        if (!restrictedBgActivity && !isHomeProcess) {
            mService.resumeAppSwitches();
        }

        mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,//4----------4
                request.voiceInteractor, startFlags, true /* doResume */, checkedOptions,
                inTask, inTaskFragment, restrictedBgActivity, intentGrants);

        if (request.outActivity != null) {
            request.outActivity[0] = mLastStartActivityRecord;
        }

        return mLastStartActivityResult;
    }

这个方法是在是非常长,我们截取部分重要的代码,在看代码之前我们先看一眼它的注释:

Executing activity start request and starts the journey of starting an activity. Here begins with performing several preliminary checks. The normally activity launch flow will go through startActivityUnchecked to startActivityInner.

翻译过来就是:执行活动启动请求并开始启动活动的旅程。这里从执行几个初步检查开始。正常的活动启动流程将通过startActivityUnchecked为startActivityInner。

接下来看代码,注释一处将会获得要启动Activity的进程,然后会在注释二处进行判断,所以说启动一个应用程序的Activity前是必须要创建出它的进程的。接着在注释三处,创建出了一个ActivityRecord的实例,前面说到过这个类是用来描述Activity的信息的,在这里就是描述的是要启动的Activity的信息。接着在注释四处就进入到了另一个方法中开始继续启动Activity。所以继续看startActivityUnchecked方法:

private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, Task inTask,
            TaskFragment inTaskFragment, boolean restrictedBgActivity,
            NeededUriGrants intentGrants) {
        int result = START_CANCELED;
        final Task startedActivityRootTask;

        final TransitionController transitionController = r.mTransitionController;
        Transition newTransition = (!transitionController.isCollecting()
                && transitionController.getTransitionPlayer() != null)
                ? transitionController.createTransition(TRANSIT_OPEN) : null;
        RemoteTransition remoteTransition = r.takeRemoteTransition();
        if (newTransition != null && remoteTransition != null) {
            newTransition.setRemoteTransition(remoteTransition);
        }
        transitionController.collect(r);
        try {
            mService.deferWindowLayout();
            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
            result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, doResume, options, inTask, inTaskFragment, restrictedBgActivity,
                    intentGrants);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
            startedActivityRootTask = handleStartResult(r, options, result, newTransition,
                    remoteTransition);
            mService.continueWindowLayout();
        }
        postStartActivityProcessing(r, result, startedActivityRootTask);

        return result;
    }

看一眼注释先:

Start an activity while most of preliminary checks has been done and caller has been confirmed that holds necessary permissions to do so. Here also ensures that the starting activity is removed if the start wasn’t successful.

翻译:启动活动时,大多数初步检查已经完成,并确认调用方拥有执行该活动所需的权限。这里还确保在启动不成功时删除启动活动。

这里它首先会调用startActivityInner方法启动Activity,最后在finally中用handleStartResult处理结果。我们先看startActivityInner方法:

    int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, Task inTask,
            TaskFragment inTaskFragment, boolean restrictedBgActivity,
            NeededUriGrants intentGrants) {
        setInitialState(r, options, inTask, inTaskFragment, doResume, startFlags, sourceRecord,
                voiceSession, voiceInteractor, restrictedBgActivity);

        computeLaunchingTaskFlags();

        computeSourceRootTask();

      	.........

        final boolean isTaskSwitch = startedTask != prevTopTask && !startedTask.isEmbedded();
        mTargetRootTask.startActivityLocked(mStartActivity, topRootTask, newTask, isTaskSwitch,
                mOptions, sourceRecord);//1-------1
        if (mDoResume) {
            final ActivityRecord topTaskActivity = startedTask.topRunningActivityLocked(); //2-------2
            if (!mTargetRootTask.isTopActivityFocusable()
                    || (topTaskActivity != null && topTaskActivity.isTaskOverlay()
                    && mStartActivity != topTaskActivity)) {
                // If the activity is not focusable, we can't resume it, but still would like to
                // make sure it becomes visible as it starts (this will also trigger entry
                // animation). An example of this are PIP activities.
                // Also, we don't want to resume activities in a task that currently has an overlay
                // as the starting activity just needs to be in the visible paused state until the
                // over is removed.
                // Passing {@code null} as the start parameter ensures all activities are made
                // visible.
                mTargetRootTask.ensureActivitiesVisible(null /* starting */,
                        0 /* configChanges */, !PRESERVE_WINDOWS);
                // Go ahead and tell window manager to execute app transition for this activity
                // since the app transition will not be triggered through the resume channel.
                mTargetRootTask.mDisplayContent.executeAppTransition();
            } else {
                // If the target root-task was not previously focusable (previous top running
                // activity on that root-task was not visible) then any prior calls to move the
                // root-task to the will not update the focused root-task.  If starting the new
                // activity now allows the task root-task to be focusable, then ensure that we
                // now update the focused root-task accordingly.
                if (mTargetRootTask.isTopActivityFocusable()
                        && !mRootWindowContainer.isTopDisplayFocusedRootTask(mTargetRootTask)) {
                    mTargetRootTask.moveToFront("startActivityInner");
                }
                mRootWindowContainer.resumeFocusedTasksTopActivities(
                        mTargetRootTask, mStartActivity, mOptions, mTransientLaunch); //3------3
            }
        }
        mRootWindowContainer.updateUserRootTask(mStartActivity.mUserId, mTargetRootTask);

        // Update the recent tasks list immediately when the activity starts
        mSupervisor.mRecentTasks.add(startedTask);
        mSupervisor.handleNonResizableTaskIfNeeded(startedTask,
                mPreferredWindowingMode, mPreferredTaskDisplayArea, mTargetRootTask);

        // If Activity's launching into PiP, move the mStartActivity immediately to pinned mode.
        // Note that mStartActivity and source should be in the same Task at this point.
        if (mOptions != null && mOptions.isLaunchIntoPip()
                && sourceRecord != null && sourceRecord.getTask() == mStartActivity.getTask()) {
            mRootWindowContainer.moveActivityToPinnedRootTask(mStartActivity,
                    sourceRecord, "launch-into-pip");
        }

        return START_SUCCESS;
    }

老规矩,先来看一眼注释:启动一个活动,并确定该活动是应该添加到现有任务的顶部,还是应该向现有活动交付新的意图。还将活动任务操作到请求的或有效的根任务/显示上。注意:这个方法只能从startActivityUnchecked调用。

首先,这个方法会通过一系列的方法调用和计算,确定了目标任务(targetTask)和启动参数(launchParams)。然后,检查是否允许在指定任务上启动活动,并返回相应的启动结果。如果不允许启动,则会发送 RESULT_CANCELED 的结果给启动活动的结果接收者。

接着我们看注释一处,这里调用了Task类的startActivityLocked,虽然叫做startActivityLocked,但是这个方法并没有真正地启动Activity,它所做的是一些预处理和准备工作。注释二处调用topRunningActivityLocked() 获取位于 startedTask 任务堆栈顶部正在运行的活动(Activity)。

在接下来的if块中将会判断获取到的Activity,if (!mTargetRootTask.isTopActivityFocusable() || …这一行代码开始一个条件语句块,用于判断目标任务堆栈是否可见或是否需要执行特殊处理。条件包括:

  • 如果目标任务堆栈的顶部活动不可见或顶部活动是一个任务叠加层(Task Overlay)并且不是启动的活动本身,则执行以下操作:
    • 确保目标任务堆栈中的所有活动都可见。
    • 执行应用程序切换动画。
  • 否则,如果目标任务堆栈之前不可见并且现在可见,并且目标任务堆栈不是当前焦点所在的任务堆栈,则将目标任务堆栈移动到前台。

显然,我们要启动的Activity将会进入到第二个分支当中,接下来看注释三处的resumeFocusedTasksTopActivities方法:

 boolean resumeFocusedTasksTopActivities(
            Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions,
            boolean deferPause) {
        if (!mTaskSupervisor.readyToResume()) {
            return false;
        }

        boolean result = false;
        if (targetRootTask != null && (targetRootTask.isTopRootTaskInDisplayArea()
                || getTopDisplayFocusedRootTask() == targetRootTask)) {
            result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions,
                    deferPause); //1----------1
        }

       .........

        return result;
    }

这里我们就看注释一处的跳转,会跳转到resumeTopActivityUncheckedLocked方法,然后在这个方法中又会跳转到resumeTopActivityInnerLocked方法中,接下来又会跳转到ActivityTaskSupervisor的startSpecificActivity方法中,最后会跳转到ActivityTaskSupervisor的realStartActivityLocked方法中,我们来看其中的一段重要代码:

  final ClientTransaction clientTransaction = ClientTransaction.obtain(
                        proc.getThread(), r.token);

                final boolean isTransitionForward = r.isTransitionForward();
                final IBinder fragmentToken = r.getTaskFragment().getFragmentToken();
                clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
                        System.identityHashCode(r), r.info,
                        // TODO: Have this take the merged configuration instead of separate global
                        // and override configs.
                        mergedConfiguration.getGlobalConfiguration(),
                        mergedConfiguration.getOverrideConfiguration(), r.compat,
                        r.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor,
                        proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(),
                        results, newIntents, r.takeOptions(), isTransitionForward,
                        proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
                        r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken));

                // Set desired final state.
                final ActivityLifecycleItem lifecycleItem;
                if (andResume) {
                    lifecycleItem = ResumeActivityItem.obtain(isTransitionForward);
                } else {
                    lifecycleItem = PauseActivityItem.obtain();
                }
                clientTransaction.setLifecycleStateRequest(lifecycleItem);

                // Schedule transaction.
                mService.getLifecycleManager().scheduleTransaction(clientTransaction);

实际上就是通过这段代码继续启动Activity的,这里新创建了一个客户端事务,用于远程调用的,点开mService.getLifecycleManager().scheduleTransaction(clientTransaction)方法:

    void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
        final IApplicationThread client = transaction.getClient();
        transaction.schedule();
        if (!(client instanceof Binder)) {
            // If client is not an instance of Binder - it's a remote call and at this point it is
            // safe to recycle the object. All objects used for local calls will be recycled after
            // the transaction is executed on client in ActivityThread.
            transaction.recycle();
        }
    }

我们看中间注释的翻译://如果client不是bind的实例,它是一个远程调用,此时回收对象是安全的。所有用于本地调用的对象将在//在ActivityThread的客户端上执行事务后被回收。所以说这里将会跳转到ActivityThread中运行,到这里我们就已经进入到ActivityThread中了。那为什么我们要说从ATMS到ApplicationThread呢?因为ApplicationThread是ActivityThread的内部类,实际上是实现了AIDL的类,也就是我们远程调用到的类:

private class ApplicationThread extends IApplicationThread.Stub {
        private static final String DB_INFO_FORMAT = "  %8s %8s %14s %14s  %s";

        public final void scheduleReceiver(Intent intent, ActivityInfo info,
                CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
                boolean sync, int sendingUser, int processState) {
            updateProcessState(processState, false);
            ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
                    sync, false, mAppThread.asBinder(), sendingUser);
            r.info = info;
            r.compatInfo = compatInfo;
            ............
}

所以我们总结下来就是ATMS通过远程操控应用程序在其进程中调用其ActivityThread类来创建Activity:
Android进阶 四大组件的工作过程(一):Activity的工作过程

ActivityThread启动Activity

接下来是最后一部分,已经跳转到了ActivityThread中了。前面说到,在ATMS中已经通过远程调用发送了客户端事务了,接下来就需要在ActivityThread中处理这些事务了。在ActivityThread中是通过Handler来处理的,我们可以看这个Handler中的一些标志位:

case BIND_APPLICATION: return "BIND_APPLICATION";
                    case EXIT_APPLICATION: return "EXIT_APPLICATION";
                    case RECEIVER: return "RECEIVER";
                    case CREATE_SERVICE: return "CREATE_SERVICE";
                    case SERVICE_ARGS: return "SERVICE_ARGS";
                    case STOP_SERVICE: return "STOP_SERVICE";
                    case CONFIGURATION_CHANGED: return "CONFIGURATION_CHANGED";
                    case CLEAN_UP_CONTEXT: return "CLEAN_UP_CONTEXT";
                    case GC_WHEN_IDLE: return "GC_WHEN_IDLE";
                    case BIND_SERVICE: return "BIND_SERVICE";
                    case UNBIND_SERVICE: return "UNBIND_SERVICE";
                    case DUMP_SERVICE: return "DUMP_SERVICE";
                    case LOW_MEMORY: return "LOW_MEMORY";
                    case PROFILER_CONTROL: return "PROFILER_CONTROL";
                    case CREATE_BACKUP_AGENT: return "CREATE_BACKUP_AGENT";
                    case DESTROY_BACKUP_AGENT: return "DESTROY_BACKUP_AGENT";
                    case SUICIDE: return "SUICIDE";
                    case REMOVE_PROVIDER: return "REMOVE_PROVIDER";
                    case DISPATCH_PACKAGE_BROADCAST: return "DISPATCH_PACKAGE_BROADCAST";
                    case SCHEDULE_CRASH: return "SCHEDULE_CRASH";
                    case DUMP_HEAP: return "DUMP_HEAP";
                    case DUMP_ACTIVITY: return "DUMP_ACTIVITY";
                    case SET_CORE_SETTINGS: return "SET_CORE_SETTINGS";
                    case UPDATE_PACKAGE_COMPATIBILITY_INFO: return "UPDATE_PACKAGE_COMPATIBILITY_INFO";
                    case DUMP_PROVIDER: return "DUMP_PROVIDER";
                    case UNSTABLE_PROVIDER_DIED: return "UNSTABLE_PROVIDER_DIED";
                    case REQUEST_ASSIST_CONTEXT_EXTRAS: return "REQUEST_ASSIST_CONTEXT_EXTRAS";
                    case TRANSLUCENT_CONVERSION_COMPLETE: return "TRANSLUCENT_CONVERSION_COMPLETE";
                    case INSTALL_PROVIDER: return "INSTALL_PROVIDER";
                    case ON_NEW_ACTIVITY_OPTIONS: return "ON_NEW_ACTIVITY_OPTIONS";
                    case ENTER_ANIMATION_COMPLETE: return "ENTER_ANIMATION_COMPLETE";
                    case LOCAL_VOICE_INTERACTION_STARTED: return "LOCAL_VOICE_INTERACTION_STARTED";
                    case ATTACH_AGENT: return "ATTACH_AGENT";
                    case APPLICATION_INFO_CHANGED: return "APPLICATION_INFO_CHANGED";
                    case RUN_ISOLATED_ENTRY_POINT: return "RUN_ISOLATED_ENTRY_POINT";
                    case EXECUTE_TRANSACTION: return "EXECUTE_TRANSACTION";
                    case RELAUNCH_ACTIVITY: return "RELAUNCH_ACTIVITY";
                    case PURGE_RESOURCES: return "PURGE_RESOURCES";
                    case ATTACH_STARTUP_AGENTS: return "ATTACH_STARTUP_AGENTS";
                    case UPDATE_UI_TRANSLATION_STATE: return "UPDATE_UI_TRANSLATION_STATE";
                    case SET_CONTENT_CAPTURE_OPTIONS_CALLBACK:
                        return "SET_CONTENT_CAPTURE_OPTIONS_CALLBACK";
                    case DUMP_GFXINFO: return "DUMP GFXINFO";
                    case INSTRUMENT_WITHOUT_RESTART: return "INSTRUMENT_WITHOUT_RESTART";
                    case FINISH_INSTRUMENTATION_WITHOUT_RESTART:
                        return "FINISH_INSTRUMENTATION_WITHOUT_RESTART";
                    case DUMP_RESOURCES: return "DUMP_RESOURCES";

每一个标志都代表一些事件的处理,而我们需要知道的是启动Activity的标志,在这里,启动Activity的标志是RELAUNCH_ACTIVITY,接下来会在Handler的handleMessage方法中进行处理:

 case RELAUNCH_ACTIVITY:
                    handleRelaunchActivityLocally((IBinder) msg.obj);
                    break;

接下来会继续跳转到handleRelaunchActivityInner方法中,这个方法然后继续会跳转,跳转到handleLaunchActivity方法,我们直接看最后的这个方法:

    public Activity handleLaunchActivity(ActivityClientRecord r,
            PendingTransactionActions pendingActions, Intent customIntent) {
		..........
        WindowManagerGlobal.initialize();

        // Hint the GraphicsEnvironment that an activity is launching on the process.
        GraphicsEnvironment.hintActivityLaunch();

        final Activity a = performLaunchActivity(r, customIntent);//1-----1

        if (a != null) {
            r.createdConfig = new Configuration(mConfigurationController.getConfiguration());
            reportSizeConfigurations(r);
            if (!r.activity.mFinished && pendingActions != null) {
                pendingActions.setOldState(r.state);
                pendingActions.setRestoreInstanceState(true);
                pendingActions.setCallOnPostCreate(true);
            }
        } else {
            // If there was an error, for any reason, tell the activity manager to stop us.
            ActivityClient.getInstance().finishActivity(r.token, Activity.RESULT_CANCELED,
                    null /* resultData */, Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
        }

        return a;
    }

我们直接看注释一处就行,会调用到performLauncherActivity方法,我们着重来分析这个方法:

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ActivityInfo aInfo = r.activityInfo;
        if (r.packageInfo == null) {
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
        }

        ComponentName component = r.intent.getComponent();
        if (component == null) {
            component = r.intent.resolveActivity(
                mInitialApplication.getPackageManager());
            r.intent.setComponent(component);
        }

        if (r.activityInfo.targetActivity != null) {
            component = new ComponentName(r.activityInfo.packageName,
                    r.activityInfo.targetActivity);
        }

        ContextImpl appContext = createBaseContextForActivity(r);//1-----1
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);//2------2
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo),
                    appContext.getAttributionSource());
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        }
        ...........

                appContext.setOuterContext(activity);
                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.activityConfigCallback,
                        r.assistToken, r.shareableActivityToken);//3-------3

                if (customIntent != null) {
                    activity.mIntent = customIntent;
                }
                r.lastNonConfigurationInstances = null;
                checkAndBlockForNetworkAccess();
                activity.mStartedActivity = false;
                int theme = r.activityInfo.getThemeResource();
                if (theme != 0) {
                    activity.setTheme(theme);
                }

                if (r.mActivityOptions != null) {
                    activity.mPendingOptions = r.mActivityOptions;
                    r.mActivityOptions = null;
                }
                activity.mLaunchedFromBubble = r.mLaunchedFromBubble;
                activity.mCalled = false;
                // Assigning the activity to the record before calling onCreate() allows
                // ActivityThread#getActivity() lookup for the callbacks triggered from
                // ActivityLifecycleCallbacks#onActivityCreated() or
                // ActivityLifecycleCallback#onActivityPostCreated().
                r.activity = activity;
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);//4---------4
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
              	..........
            }
            r.setState(ON_CREATE);//5----------5

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

首先在注释一处的ContextImpl appContext = createBaseContextForActivity®,主要是创建出了上下文对象,这个我们应该很熟悉;
注释二处,通过ClassLoader和Instrumentation创建出了Activity的实例;
注释三处,调用到了创建出的activity的attach方法,activity.attach() 方法是用于将 Activity 附加到系统的 ActivityThread 中,并进行一系列初始化和配置操作。具体来说,attach() 方法接收多个参数,每个参数都用于设置 Activity 的不同属性和状态;
注释四处无论如何都会调用mInstrumentation.callActivityOnCreate方法,这个方法很简单,主要是调用到activity的performCreate方法,在这个方法中,Activity的onCreate方法被正式调用;那么到这里,Activity就算正式启动了;
注释五处调用setState方法更新了Activity的状态,更新到了ON_CREATE;

Resume的启动

那么最后要讲的是启动Resume的过程,这里的流程和之前Android8.0的源码相比有较大不同,这里我也是仅做猜测,大家酌情查看。让我们回到之前一开始的handleRelaunchActivityLocally方法:

public void handleRelaunchActivityLocally(IBinder token) {
        final ActivityClientRecord r = mActivities.get(token);
        if (r == null) {
            Log.w(TAG, "Activity to relaunch no longer exists");
            return;
        }

        final int prevState = r.getLifecycleState();

        if (prevState < ON_START || prevState > ON_STOP) {
            Log.w(TAG, "Activity state must be in [ON_START..ON_STOP] in order to be relaunched,"
                    + "current state is " + prevState);
            return;
        }

        ActivityClient.getInstance().activityLocalRelaunch(r.token);//1----------1
        // Initialize a relaunch request.
        final MergedConfiguration mergedConfiguration = new MergedConfiguration(
                r.createdConfig != null
                        ? r.createdConfig : mConfigurationController.getConfiguration(),
                r.overrideConfig);
        final ActivityRelaunchItem activityRelaunchItem = ActivityRelaunchItem.obtain(
                null /* pendingResults */, null /* pendingIntents */, 0 /* configChanges */,
                mergedConfiguration, r.mPreserveWindow);
        // Make sure to match the existing lifecycle state in the end of the transaction.
        final ActivityLifecycleItem lifecycleRequest =
                TransactionExecutorHelper.getLifecycleRequestForCurrentState(r);
        // Schedule the transaction.
        final ClientTransaction transaction = ClientTransaction.obtain(this.mAppThread, r.token);
        transaction.addCallback(activityRelaunchItem);
        transaction.setLifecycleStateRequest(lifecycleRequest);
        executeTransaction(transaction);//2--------2
    }

我们知道在之前的注释一处的的activityLocalRelaunch方法完成了Activity的Launch并且更新了Activity的状态为ON_CREATE了,最后几行代码中又会根据LifeCycle状态来执行事务,主要看注释二处的executeTransaction方法,最后会调用到TransactionExecutor的execute方法,我们接下来就紧接着看execute方法:

 public void execute(ClientTransaction transaction) {
        if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Start resolving transaction");

        final IBinder token = transaction.getActivityToken();
        if (token != null) {
            final Map<IBinder, ClientTransactionItem> activitiesToBeDestroyed =
                    mTransactionHandler.getActivitiesToBeDestroyed();
            final ClientTransactionItem destroyItem = activitiesToBeDestroyed.get(token);
            if (destroyItem != null) {
                if (transaction.getLifecycleStateRequest() == destroyItem) {
                    activitiesToBeDestroyed.remove(token);
                }
                if (mTransactionHandler.getActivityClient(token) == null) {
                    Slog.w(TAG, tId(transaction) + "Skip pre-destroyed transaction:\n"
                            + transactionToString(transaction, mTransactionHandler));
                    return;
                }
            }
        }

        if (DEBUG_RESOLVER) Slog.d(TAG, transactionToString(transaction, mTransactionHandler));

        executeCallbacks(transaction);

        executeLifecycleState(transaction);//1----------1
        mPendingActions.clear();
        if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "End resolving transaction");
    }

接下来会进入到注释一处的executeLifecycleState方法:

private void executeLifecycleState(ClientTransaction transaction) {
        final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
		............

        // Cycle to the state right before the final requested state.
        cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */, transaction);//1---------1

        // Execute the final transition with proper parameters.
        lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
        lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);
    }

接下来会调用到注释一处的cycleToPath方法,最后会调用到TransactionExecutor的performLifecycleSequence方法,这个方法就会根据Activity的状态来执行响应的回调:

switch (state) {
                case ON_CREATE:
                    mTransactionHandler.handleLaunchActivity(r, mPendingActions,
                            null /* customIntent */);
                    break;
                case ON_START:
                    mTransactionHandler.handleStartActivity(r, mPendingActions,
                            null /* activityOptions */);
                    break;
                case ON_RESUME:
                    mTransactionHandler.handleResumeActivity(r, false /* finalStateRequest */,
                            r.isForward, "LIFECYCLER_RESUME_ACTIVITY");
                    break;
                case ON_PAUSE:
                    mTransactionHandler.handlePauseActivity(r, false /* finished */,
                            false /* userLeaving */, 0 /* configChanges */, mPendingActions,
                            "LIFECYCLER_PAUSE_ACTIVITY");
                    break;
                case ON_STOP:
                    mTransactionHandler.handleStopActivity(r, 0 /* configChanges */,
                            mPendingActions, false /* finalStateRequest */,
                            "LIFECYCLER_STOP_ACTIVITY");
                    break;
                case ON_DESTROY:
                    mTransactionHandler.handleDestroyActivity(r, false /* finishing */,
                            0 /* configChanges */, false /* getNonConfigInstance */,
                            "performLifecycleSequence. cycling to:" + path.get(size - 1));
                    break;
                case ON_RESTART:
                    mTransactionHandler.performRestartActivity(r, false /* start */);
                    break;
                default:
                    throw new IllegalArgumentException("Unexpected lifecycle state: " + state);
            }

这样就会开启各自的生命周期的回调了,包括Resume,之后会调用对应的handle方法,比如对Resume来说就会进入handleResumeActivity方法中,然后执行对应的perform方法执行activity的回调:

public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
            boolean isForward, 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;

        // TODO Push resumeArgs into the activity for consideration
        // skip below steps for double-resume and r.mFinish = true case.
        if (!performResumeActivity(r, finalStateRequest, reason)) {
            return;
        }
        if (mActivitiesToBeDestroyed.containsKey(r.token)) {
            // Although the activity is resumed, it is going to be destroyed. So the following
            // UI operations are unnecessary and also prevents exception because its token may
            // be gone that window manager cannot recognize it. All necessary cleanup actions
            // performed below will be done while handling destruction.
            return;
        }
        ......
   }

总之就是通过对应的ActivityThread对象来管理Activity的生命周期以及其回调。

根Activity启动过程中涉及到的进程

根Activity做为一个应用程序要启动的第一个Activity,其涉及到的进程比一般的Activity要多,因为它还涉及到自身进程的创建。总的来说,它会涉及到四个进程,分别是Zygote进程,Launcher进程,AMS和ATMS进程和要启动的应用程序进程,我们可以用下面这幅图来总结一下:
Android进阶 四大组件的工作过程(一):Activity的工作过程文章来源地址https://www.toymoban.com/news/detail-486561.html

到了这里,关于Android进阶 四大组件的工作过程(一):Activity的工作过程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android Activity启动过程详解

    1,《android系统启动流程简介》 2,《android init进程启动流程》 3,《android zygote进程启动流程》 4,《Android SystemServer进程启动流程》 5,《android launcher启动流程》 6,《Android Activity启动过程详解》 1,《Android 源码下载和编译》 2,《android 11源码编译和pixel3 刷机》 3,《Andro

    2024年02月09日
    浏览(15)
  • Activity启动过程详解(Android 12源码分析)

    启动一个Activity,通常有两种情况,一种是在应用内部启动Activity,另一种是Launcher启动 1、应用内启动 通过startActivity来启动Activity 启动流程: 一、Activity启动的发起 二、Activity的管理——ATMS 三、线程切换即消息处理——mH 四、Activity启动核心实现——初始化及生命周期 2、

    2024年02月13日
    浏览(13)
  • Android四大组件之服务

    为什么要使用服务呢? 从上面的文字说,我们知道这个服务是用于执行长期后台运行的操作。有些时候,我们没有界面,但是程序仍然需要工作。比如说,我们播放音乐,在后台播放音乐。比如说,我们下载任务,在后台下载文件。这些都是没有界面 的后台运行程序,这些

    2024年02月14日
    浏览(23)
  • [Android 四大组件] --- Service

    Service是Android系统中的四大组件之一,它是一种长生命周期的,没有可视化界面,运行于后台的一种服务程序。 1 通过按钮\\\"开始服务\\\"启动service 2 创建StartService 继承service类 在StartService中实现 onBind,onCreate,onStartCommand, onDestroy方法 3 在AndroidManifest.xml 清单文件中注册 4 运行结

    2024年02月10日
    浏览(14)
  • Android 四大组件之广播

    在Android应用开发中,广播组件是一项关键技术,被广泛用于各种任务和场景。无论是发送系统级广播,还是在应用内部实现组件间的通信,了解和掌握广播组件的工作原理和使用方法对于每个Android开发者来说都是至关重要的。本文旨在帮助你深入了解Android广播组件,并给出

    2024年02月06日
    浏览(21)
  • [Android 四大组件] --- BroadcastReceiver

    BroadcastReceiver(广播接收器)即广播,是一个全局的监听器。 Android 广播分为两个角色:广播发送者、广播接受者。 广播按照类型分为两种,一种是全局广播,另一种是本地广播 全局广播:就是发出的广播被其他任意应用程序接收,或者可以接收来自其他任意应用程序的广播

    2024年02月10日
    浏览(14)
  • Android 四大组件启动

    service: startService启动过程分析 - Gityuan博客 | 袁辉辉的技术博客 在整个startService过程,从进程角度看服务启动过程 Process A进程: 是指调用startService命令所在的进程,也就是启动服务的发起端进程,比如点击桌面App图标,此处Process A便是Launcher所在进程。 system_server进程: 系统

    2024年04月11日
    浏览(13)
  • Android Studio —— Activity组件(课后作业:登录和注册App)

    运行效果图   主界面(初始),注册界面,登录界面,主界面(注册和登录之后) 实现步骤 1.设计主界面,编写activity_main.xml 注:(1) 按钮的格式是自己设计的,如下 注:(2)需编写strings.xml 2.创建两个activity(会自动创建对应的layout布局文件)   3.设计登录和注册界面,编写

    2024年02月05日
    浏览(14)
  • Android入门教程 | 四大组件之Service(前台服务,后台服务)

    Service是一种可在后台执行长时间运行操作而不提供界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。 此外,组件可通过绑定到服务与之进行交互,甚至是执行进程间通信 (IPC)。 例如,服务可在后台处理网络事务、播放

    2024年02月05日
    浏览(22)
  • Android端MVVM从入门到实战(第一篇) - MVVM和四大官方组件

    MVVM是相对于MVC和MVP的一个概念,是一种架构模式。 1.1 MVC 传统的MVC中,View改变通知Controller进行处理,Controller处理结束后通知Model层更新,Model层更新以后通知View层渲染,指令单项流动,角色分工明确。但是MVC有三个缺点,1、三个角色互相持有对方依赖,因此很难复用其中任

    2024年02月04日
    浏览(15)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包