GVKun编程网logo

android startactivity 报错(android startactivity无效)

1

在本文中,我们将详细介绍androidstartactivity报错的各个方面,并为您提供关于androidstartactivity无效的相关解答,同时,我们也将为您带来关于Ablepsia和sta

在本文中,我们将详细介绍android startactivity 报错的各个方面,并为您提供关于android startactivity无效的相关解答,同时,我们也将为您带来关于Ablepsia 和 startActivity() 说再见、AMS startActivity()、Android 10 startActivity 源码分析、Android SingleTask 和使用 StartActivity(Intent) 似乎调用 onCreate() 方法?的有用知识。

本文目录一览:

android startactivity 报错(android startactivity无效)

android startactivity 报错(android startactivity无效)

       at dalvik.system.NativeStart.main(Native Method)
     Caused by: java.lang.NullPointerException
            at android.app.LoadedApk.initializeJavaContextClassLoader(LoadedApk.java:377)
            at android.app.LoadedApk.getClassLoader(LoadedApk.java:320)
            at android.app.LoadedApk.makeApplication(LoadedApk.java:493)
            at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4238)
            at android.app.ActivityThread.access$1400(ActivityThread.java:140)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1297)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:4935)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805)
            at dalvik.system.NativeStart.main(Native Method)
07-17 20:17:59.316  28301-28301/com.qingmedia.zhoudao E/LogUtils [error, 49]﹕ 检测到严重错误,程序即将退出
    java.lang.NullPointerException
            at com.zhy.android.percent.support.PercentLayoutHelper.shouldHandleMeasuredHeightTooSmall(PercentLayoutHelper.java:447)
            at com.zhy.android.percent.support.PercentLayoutHelper.handleMeasuredStateTooSmall(PercentLayoutHelper.java:422)
            at com.zhy.android.percent.support.PercentRelativeLayout.onMeasure(PercentRelativeLayout.java:89)
            at android.view.View.measure(View.java:15557)
            at android.widget.RelativeLayout.measureChild(RelativeLayout.java:602)
            at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:415)
            at com.zhy.android.percent.support.PercentRelativeLayout.onMeasure(PercentRelativeLayout.java:88)
            at android.view.View.measure(View.java:15557)
            at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:617)
            at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:399)
            at android.view.View.measure(View.java:15557)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5114)
            at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1396)
            at android.widget.LinearLayout.measureVertical(LinearLayout.java:681)
            at android.widget.LinearLayout.onMeasure(LinearLayout.java:574)
            at com.zhy.android.percent.support.PercentLinearLayout.onMeasure(PercentLinearLayout.java:29)
            at android.view.View.measure(View.java:15557)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5114)
            at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
            at android.view.View.measure(View.java:15557)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5114)
            at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1396)
            at android.widget.LinearLayout.measureVertical(LinearLayout.java:681)
            at android.widget.LinearLayout.onMeasure(LinearLayout.java:574)
            at android.view.View.measure(View.java:15557)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5114)
            at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
            at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2397)
            at android.view.View.measure(View.java:15557)
            at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2001)
            at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1242)
            at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1417)
            at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1135)
            at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4579)
            at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)
            at android.view.Choreographer.doCallbacks(Choreographer.java:555)
            at android.view.Choreographer.doFrame(Choreographer.java:525)
            at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)
            at android.os.Handler.handleCallback(Handler.java:615)
            at android.os.Handler.dispatchMessage(Handler.java:92)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:4935)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805)
            at dalvik.system.NativeStart.main(Native Method)

Ablepsia 和 startActivity() 说再见

Ablepsia 和 startActivity() 说再见

Ablepsia 是一个可以简化 startActivity() 简化参数传递、view元素过渡分享动画、拦截、重定向、多重重定向、保证跳转存活的轻量级框架

Ablepsia - git 项目地址点这里

曾经你在代码里写了无数遍判断之后的各种混乱跳转、曾经写过无数次的跳转工具类,现在终于来帮你提供解决方案了

曾经有一个用户详情页需要在已登录的前提下才能打开,于是我写了一个跳转工具类,增加了一个打开用户详情页方法,判断没登陆就打开登录页面,···嗯嗯我日,登录后怎么继续打开用户详情页,回调?好吧,那就回调吧。后来又来了一个好友列表也要已登录才能打开,于是我又增加一个方法,后来又来了50+个也要已登录才能打开,于是又增加了50+个方法,增加了50+个回调

我问了自己无数次

对于上述栗子,Ablepsia 的处理姿势十分优雅,将 50+ 变为 1 次判断,自动重定向到登录页面,登录成功后自动跳转到用户详情页面,没有一个回调。整个过程无需开发者干预。你若还有别的跳转条件,比如什么打开某个页面之前需要检查wifi状态啊,检查用户身份啊等等,那都不算事了。

屁话说多了啊,看看效果吧

Demo 在 git 上 https://github.com/Xiao187/Ab...

如上糟糕的GIF所示 ,第一次未登录状态下打开 用户详情页,将会被重定向到 登录页,点击登录成功后继续跳转到用户详细页,第二次已登录状态打开 用户详情页,直接跳转到 用户详情页,并将 view 过渡分享过去。由于第一次跳转被重定向,所以 view 分享的动画被强制丢失了,原因是考虑到重定向之后的元素分享会错乱

OK,接下来介绍使用姿势

  • 配置 gradle
    //项目的 build.gradle 添加如下
    allprojects {
        repositories {
            ...
            maven { url "https://jitpack.io" }
        }
    }
    // 模块的 build.gradle 添加如下
    dependencies {
            compile ''com.github.Xiao187:Ablepsia:v1.0.7''
    }
  • 使用
        //打开 UseInfoActivity
        Ablepsia.open(this, UseInfoActivity.class);
        //打开 UseInfoActivity 带参数,支持所有类型
        Ablepsia.kv("name","jack").open(this, UseInfoActivity.class);
        //打开 UseInfoActivity 指定 flag
        Ablepsia.flag(Intent.FLAG_ACTIVITY_NEW_TASK)
                    .open(this, UseInfoActivity.class);
        //打开 UseInfoActivity 分享元素
        Ablepsia.options(ActivityOptionsCompat.makeSceneTransitionAnimation(this, view, "name").toBundle())
                    .open(this, UseInfoActivity.class);
  • 拦截 - 重定向
//在需要拦截或重定向的 Activity 上 使用 @Symptom 注解
@Symptom("需要登录才能打开")
public class UseInfoActivity extends AppCompatActivity {}
//自定义 Doctor 继承 Doctor
public class DemoDoctor extends Doctor {

    @Override
    protected Anagraph treatment(String symptom, Context context, Class blind) {}
    
    @Override
    protected void funeral(String symptom, Context context, Class<? extends Activity> activity) {
        //调用 Anagraph.die() 后,会回调到这里
        //默认空实现
    }
}
    // Ablepsia.open() 之前设置 Doctor,否则不会拦截
    Ablepsia.setDoctor(new DemoDoctor());
    //在 treatment 方法中实现拦截,不能 return null;
    @Override
    protected Anagraph treatment(String symptom, Context context, Class blind) {
        switch (symptom) {
                case "需要登录才能打开":
                    if (SignInStatus.isSign()){
                        return Anagraph.alive();// -- 继续执行
                    }else {
                        Ablepsia.open(context,SignInActivity.class); //打开登录页面

                        /**
                         * 拘留,直到调用 DemoDoctor.alive("先去登录") 才会继续跳转
                         * 你可以在登录成功之后调用 DemoDoctor.alive("先去登录"),将会跳转至UseInfoActivity
                         */
                        return Anagraph.detained("先去登录");
                    }
                default:
                    return Anagraph.die();// -- 终止跳转
        }
}

上述 Anagraph.detained("key"); 是指将这一次跳转拘留起来,你可以在某一时刻调用 DemoDoctor.alive("key"); 就会继续执行这一次未完成的跳转,比如,你可以在 登录成功的回调 里并且在 登录页面 finish(); 之前调用 。推荐在 finish(); 之前调用的原因是画面可以更流畅,不信的话你可以试试在 finish(); 之后调用

除了上述 Anagraph.alive();Anagraph.detained("key");Anagraph.die(); 三种方式,还有一种不推荐的处理方式,使用 Chaperonage 监视:

    //默认每 500 毫秒监视一次,你可以让他更快
    //当监视到 return true; 便继续这一次未完成的跳转
    return Anagraph.detained(new Anagraph.Chaperonage(/* 500 */) {
        @Override
        public boolean Chaperonage() {
               return SignInStatus.isSign();
        }
    });

Chaperonage 原理是开启了一个子线程来监视,当条件成立时便继续执行任务,不推荐在Chaperonage() 方法中做复杂的任务,由于这种方式可能产生不必要的资源浪费,所以不推荐使用,建议用Anagraph.detained("key"); 来替换。

注意事项

  • 如过不调用 Ablepsia.setDoctor();, 将会使用默认 Doctor,默认 Anagraph.alive();
  • 如果不是 return Anagraph.alive();,将会清空此次跳转携带的 options(),也就是说被重定向过的跳转将会失去 options(),原因是考虑到重定向之后的元素分享会错乱;

·
·
·

AMS startActivity()

AMS startActivity()

本篇为鸡生蛋系列第三篇文章

  1. Linux input系统数据上报流程
  2. Android InputManager分析
  3. AMS startActivity()
  4. activity显示过程梳理
  5. HomeLauncher启动

startActivity()流程极其复杂,代码庞大,牵扯到的类等也较多,
这里简单讲下流程, 更多的作为个人学习笔记。

点击Launcher图标后,Launcher也是通过startActivity()启动另一应用的,
Launcher本身流程不分析了。

AMS Android9.0
http://androidxref.com/9.0.0_r3/

参考:
Android应用程序的Activity启动过程简要介绍和学习计划
https://blog.csdn.net/luoshen...
Android深入四大组件(六)Android8.0 根Activity启动过程(前篇)
https://blog.csdn.net/itachi8...

问题
ActivityStartController ActivityStarter 是什么?作用?关系?

1. AMS init

frameworks/base/services/java/com/android/server/SystemServer.java
private void startBootstrapServices() {
......
    mActivityManagerService = mSystemServiceManager.startService(
            ActivityManagerService.Lifecycle.class).getService();
    mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
    mActivityManagerService.setInstaller(installer);

2. startActivity --> OnCreate()

frameworks/base/core/java/android/app/ContextImpl.java
有几个方法可startActivity(), 最终都调到ActivityManagerService.java里
eg:

startActivity() --> mMainThread.getInstrumentation().execStartActivity() --> startActivity()/ActivityManagerService.java --> startActivityAsUser()
startActivityAsUser() --> ... startActivityAsUser()/ActivityManagerService.java
startActivityAsUser()/ActivityManagerService.java 
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
        boolean validateIncomingUser) {
    //判断调用者进程是否被隔离   
    enforceNotIsolatedCaller("startActivity");

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

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

}

这里通过 ActivityStartController 申请了个 ActivityStarter,然后执行
frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

maywait由上面setMayWait(userId)设置, 然后调用 startActivityMayWait() 或者 startActivity()
执行完后onExecutionComplete()回调ActivityStartController的 onExecutionComplete()执行一些回收任务;

/**
 * Starts an activity based on the request parameters provided earlier.
 * @return The starter result.
 */
int execute() {
    try {
        // TODO(b/64750076): Look into passing request directly to these methods to allow
        // for transactional diffs and preprocessing.
        if (mRequest.mayWait) {
            return startActivityMayWait(mRequest.caller, mRequest.callingUid,
                    mRequest.callingPackage, mRequest.intent, mRequest.resolvedType,
                    mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
                    mRequest.resultWho, mRequest.requestCode, mRequest.startFlags,
                    mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig,
                    mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId,
                    mRequest.inTask, mRequest.reason,
                    mRequest.allowPendingRemoteAnimationRegistryLookup);
        } else {
            return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent,
                    mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo,
......
        }
    } finally {
        onExecutionComplete();
    }

private int startActivityMayWait(IApplicationThread caller, int callingUid,
        String callingPackage, Intent intent, String resolvedType,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode, int startFlags,
        ProfilerInfo profilerInfo, WaitResult outResult,
        Configuration globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity,
        int userId, TaskRecord inTask, String reason,
        boolean allowPendingRemoteAnimationRegistryLookup) {
......
        final ActivityRecord[] outRecord = new ActivityRecord[1];
        int res = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo,
                voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid,
                callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options,
                ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason,
                allowPendingRemoteAnimationRegistryLookup);
......
        if (outResult != null) {
            outResult.result = res;

            final ActivityRecord r = outRecord[0];
            // 根据返回结果进一步处理
            switch(res) {
                case START_SUCCESS: {
......
                case START_DELIVERED_TO_TOP: {
......
                case START_TASK_TO_FRONT: {
......

上面的caller为IApplicationThread
startActivity(IApplicationThread..)也有两个,最终调用到了startActivity(final ActivityRecord r..)

private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
        String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
...... //创建即将要启动的Activity的描述类ActivityRecord
    ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
            callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
            resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
            mSupervisor, checkedOptions, sourceRecord);
......
    return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
            true /* doResume */, checkedOptions, inTask, outActivity);
}
startActivity(IApplicationThread..) --> startActivity(final ActivityRecord r..)
private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity) {
    int result = START_CANCELED;
    try {
        mService.mWindowManager.deferSurfaceLayout();
        result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                startFlags, doResume, options, inTask, outActivity);
    } finally {
......
    }

    postStartActivityProcessing(r, result, mTargetStack);

    return result;
}

private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
        ActivityRecord[] outActivity) {
......

    if (reusedActivity != null) {
        ......
        reusedActivity = setTargetStackAndMoveToFrontIfNeeded(reusedActivity);
.......
    // 注释1 是否要创建新的task
    // Should this be considered a new task?
    int result = START_SUCCESS;
    if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
            && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
        newTask = true;
        // 注释2
        result = setTaskFromReuseOrCreateNewTask(taskToAffiliate, topStack);
    } else if (mSourceRecord != null) {
        result = setTaskFromSourceRecord();
    } else if (mInTask != null) {
        result = setTaskFromInTask();
    } else {
        // This not being started from an existing activity, and not part of a new task...
        // just put it in the top task, though these days this case should never happen.
        setTaskToCurrentTopOrCreateNewTask();
    }
......

    mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
            mOptions);
    if (mDoResume) {
        final ActivityRecord topTaskActivity =
                mStartActivity.getTask().topRunningActivityLocked();
        if (!mTargetStack.isFocusable()
                || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                && mStartActivity != topTaskActivity)) {
...
            mTargetStack.ensureActivitiesVisibleLocked(null, 0, !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.
            mService.mWindowManager.executeAppTransition();
        } else {
            // If the target stack was not previously focusable (previous top running activity
            // on that stack was not visible) then any prior calls to move the stack to the
            // will not update the focused stack.  If starting the new activity now allows the
            // task stack to be focusable, then ensure that we now update the focused stack
            // accordingly.
            if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
                mTargetStack.moveToFront("startActivityUnchecked");
            }
            mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                    mOptions);
        }
    } else if (mStartActivity != null) {
        mSupervisor.mRecentTasks.add(mStartActivity.getTask());
    }
    mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);

    mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredWindowingMode,
            preferredLaunchDisplayId, mTargetStack);

    return START_SUCCESS;
}

在注释1处我们得知,启动根Activity时会将Intent的Flag设置为FLAG_ACTIVITY_NEW_TASK,
这样注释1处的条件判断就会满足,
接着执行注释2处的 setTaskFromReuseOrCreateNewTask(),其内部会创建一个新的TaskRecord,
TaskRecord用来描述一个Activity任务栈,也就是说setTaskFromReuseOrCreateNewTask()内部会创建一个新的Activity任务栈

boolean resumeFocusedStackTopActivityLocked(
        ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
......
    if (targetStack != null && isFocusedStack(targetStack)) {
        return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
    }
......// 注释1 获取要启动的Activity所在栈的栈顶的不是处于停止状态的ActivityRecord
    final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
    if (r == null || !r.isState(RESUMED)) {// 注释2
        mFocusedStack.resumeTopActivityUncheckedLocked(null, null);// 注释3
    } else if (r.isState(RESUMED)) {
        // Kick off any lingering app transitions form the MoveTaskToFront operation.
        mFocusedStack.executeAppTransition(targetOptions);
    }

注释1处调用ActivityStack的topRunningActivityLocked方法获取要启动的Activity所在栈的栈顶的不是处于停止状态的ActivityRecord。
注释2处如果ActivityRecord不为null,或者要启动的Activity的状态不是RESUMED状态,
就会调用注释3处的ActivityStack的resumeTopActivityUncheckedLocked方法,对于即将要启动的Activity,
注释2的条件判断是肯定满足,因此我们来查看ActivityStack的resumeTopActivityUncheckedLocked方法

frameworks/base/services/core/java/com/android/server/am/ActivityStack.java
mFocusedStack.resumeTopActivityUncheckedLocked() --> resumeTopActivityInnerLocked() --> mStackSupervisor.startSpecificActivityLocked(next, true, false);
frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
void startSpecificActivityLocked(ActivityRecord r,
        boolean andResume, boolean checkConfig) {
    // Is this activity''s application already running?
    ProcessRecord app = mService.getProcessRecordLocked(r.processName,
            r.info.applicationInfo.uid, true);
....
    if (app != null && app.thread != null) {
......//如果app已经运行,调用realStartActivityLocked()
            realStartActivityLocked(r, app, andResume, checkConfig);
            return;
......
    }
//如果没有运行则调用AMS的startProcessLocked()
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
            "activity", r.intent.getComponent(), false, false, true);
}

realStartActivityLocked()为应用程序内部启动非默认Activity的过程,暂时不看,
我们看 startProcessLocked(),
startProcessLocked()函数也有好几个, 最终都会转为 startProcessLocked(ProcessRecord app...
ProcessRecord生成eg:
final ProcessRecord r = new ProcessRecord(this, stats, info, proc, uid);
然后进一步的调用

startProcessLocked(String hostingType,... --> startProcess(app.hostingType...
private ProcessStartResult startProcess(String hostingType, String entryPoint,
        ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
......
        if (hostingType.equals("webview_service")) {
            startResult = startWebView(entryPoint,
                    app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                    app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                    app.info.dataDir, null,
                    new String[] {PROC_START_SEQ_IDENT + app.startSeq});
        } else {
            startResult = Process.start(entryPoint,
                    app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                    app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                    app.info.dataDir, invokeWith,
                    new String[] {PROC_START_SEQ_IDENT + app.startSeq});
        }

如果hostingType为webview_service调用Process.startWebView()
否则 Process.start()

frameworks/base/core/java/android/os/Process.java
* @param processClass The class to use as the process''s main entry
*                     point.
public static final ProcessStartResult start(final String processClass,
                              final String niceName,
                              int uid, int gid, int[] gids,
                              int runtimeFlags, int mountExternal,
                              int targetSdkVersion,
                              ......) {
    // 注意 processClass 为 "android.app.ActivityThread"
    return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
}

我们重点关注下传入的参数 processClass,即 entryPoint,通过查找传传下来的参数,即为
final String entryPoint = "android.app.ActivityThread";
新的进程会导入android.app.ActivityThread类,并且执行它的main函数.
zygoteProcess.start()后面有机会再分析,我们就直接看 ActivityThread main()

frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {
......
    Looper.prepareMainLooper();

    // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
    // It will be in the format "seq=114"
    long startSeq = 0;
    if (args != null) {
        for (int i = args.length - 1; i >= 0; --i) {
            if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                startSeq = Long.parseLong(
                        args[i].substring(PROC_START_SEQ_IDENT.length()));
            }
        }
    }
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }
......
    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
}

其main函数主要为Looper准备主looper, 创建一个ActivityThread实例,然后调用它的attach函数,
接着就进入消息循环了,若loope退出则抛个异常。
attach()如果为非system则进一步调用AMS attachApplication()

private void attach(boolean system, long startSeq) {
......
    if (!system) {
        final IActivityManager mgr = ActivityManager.getService();
        try {
            mgr.attachApplication(mAppThread, startSeq);

attachApplication()--> attachApplicationLocked()
private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid, int callingUid, long startSeq) {
        } else if (app.instr != null) {
            thread.bindApplication(processName, appInfo, providers,
..
    // See if the top visible activity is waiting to run in this process...
    if (normalMode) {
        try {
            if (mStackSupervisor.attachApplicationLocked(app)) {

thread.bindApplication() 将应用进程的ApplicationThread对象绑定到ActivityManagerService,
也就是说获得ApplicationThread对象的代理对象。

mStackSupervisor.attachApplicationLocked(app)
frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java#
boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
......
            final ActivityRecord top = stack.topRunningActivityLocked();
            final int size = mTmpActivityList.size();
            for (int i = 0; i < size; i++) {
                final ActivityRecord activity = mTmpActivityList.get(i);
                if (activity.app == null && app.uid == activity.info.applicationInfo.uid
                        && processName.equals(activity.processName)) {
                    try {
                        if (realStartActivityLocked(activity, app,
                                top == activity /* andResume */, true /* checkConfig */)) {
......
}

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
         boolean andResume, boolean checkConfig) throws RemoteException {
.........
             // Create activity launch transaction.
             final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
                     r.appToken);
             clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent), <----注意这个callback,为LaunchActivityItem
                     System.identityHashCode(r), r.info,
.......
             // Schedule transaction.
             mService.getLifecycleManager().scheduleTransaction(clientTransaction);

Android9引入了ClientLifecycle和ClientTransactionHandler来辅助管理Activity生命周期,过程更麻烦了.

frameworks/base/services/core/java/com/android/server/am/ClientLifecycleManager.java
void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    final IApplicationThread client = transaction.getClient();
    transaction.schedule(); -->
frameworks/base/core/java/android/app/servertransaction/ClientTransaction.java
private IApplicationThread mClient;
public void schedule() throws RemoteException {
    mClient.scheduleTransaction(this); -->
}
frameworks/base/core/java/android/app/ActivityThread.java
private class ApplicationThread extends IApplicationThread.Stub {
......
     @Override
     public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
         ActivityThread.this.scheduleTransaction(transaction); -->
     }

ActivityThread类中并没有定义scheduleTransaction方法,所以调用的是他父类ClientTransactionHandler的 scheduleTransaction()。

frameworks/base/core/java/android/app/ClientTransactionHandler.java
void scheduleTransaction(ClientTransaction transaction) {
    transaction.preExecute(this);
    sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}

Handler接到后

frameworks/base/core/java/android/app/ActivityThread.java
public void handleMessage(Message msg) {
        case EXECUTE_TRANSACTION:
            final ClientTransaction transaction = (ClientTransaction) msg.obj;
            mTransactionExecutor.execute(transaction); -->
frameworks/base/core/java/android/app/servertransaction/TransactionExecutor.java
public void execute(ClientTransaction transaction) {
......
    executeCallbacks(transaction);

    executeLifecycleState(transaction);

上面会执行callback函数,然后再执行executeLifecycleState()
这里我们只看callback函数,注意
realStartActivityLocked()传入的callback为LaunchActivityItem

public void executeCallbacks(ClientTransaction transaction) {
    final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
......
    final int size = callbacks.size();
    for (int i = 0; i < size; ++i) {
        final ClientTransactionItem item = callbacks.get(i);
......
        item.execute(mTransactionHandler, token, mPendingActions); -->
        item.postExecute(mTransactionHandler, token, mPendingActions);
......
}

item.execute() 即调用到LaunchActivityItem.execute()

frameworks/base/core/java/android/app/servertransaction/LaunchActivityItem.java
execute() --> client.handleLaunchActivity -->
ActivityThread.java handleLaunchActivity() --> performLaunchActivity()

在ActivityThread.performLaunchActivity方法中首先对Activity的ComponentName、ContextImpl、Activity
以及Application对象进行了初始化并相互关联,
然后设置Activity主题,最后调用Instrumentation.callActivityOnCreate方法。

/**  Core implementation of activity launch. */
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
......//初始化ComponentName
    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
    ContextImpl appContext = createBaseContextForActivity(r);
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = appContext.getClassLoader();
        //初始化activity
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
       ......
    }

    try {//初始化Application
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);
......
        if (activity != null) {
....... //关联
            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.configCallback);

......//调用callActivityOnCreate
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
......
        }
        //状态设为ON_CREATE
        r.setState(ON_CREATE);
......
    return activity;
}
mInstrumentation.callActivityOnCreate() --> activity.performCreate -->
frameworks/base/core/java/android/app/Activity.java
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
......
    if (persistentState != null) {
        onCreate(icicle, persistentState);
    } else {
        onCreate(icicle);
    }
......
}

即最终调用到了我们的应用程序的onCreate()

流程图,打开
https://www.websequencediagra...
然后复制粘贴下面的内容

Title Androd9 startActivity->OnCreate流程

participant ContextImpl
participant Instrumentation
participant ActivityManagerService
participant ActivityStartController
participant ActivityStarter
participant ActivityStack
participant ActivityStackSupervisor
participant Process
participant zygoteProcess
participant ActivityThread


opt startActivity part1
    ContextImpl->+Instrumentation:startActivity() --> mMainThread.getInstrumentation()
        Instrumentation->ActivityManagerService:execStartActivity()
        ActivityManagerService->ActivityStartController:startActivityAsUser()
        ActivityStartController->ActivityStarter:obtainStarter()
        ActivityStarter->ActivityStarter:execute()
        ActivityStarter->ActivityStarter:startActivityMayWait()/startActivity(IApplicationThread...)
        ActivityStarter->ActivityStarter:startActivity(IApplicationThread...)
        ActivityStarter->ActivityStarter:startActivity(ActivityRecord...)
        ActivityStarter->+ActivityStarter:startActivityUnchecked(ActivityRecord...)
            ActivityStarter->ActivityStarter:setTaskFromReuseOrCreateNewTask()
            ActivityStarter->ActivityStackSupervisor:resumeFocusedStackTopActivityLocked()
            ActivityStackSupervisor->ActivityStack:resumeTopActivityInnerLocked()
            ActivityStack->ActivityStackSupervisor:startSpecificActivityLocked()
            alt if (app.thread != null)
                ActivityStackSupervisor->ActivityStackSupervisor:realStartActivityLocked()
            else
                ActivityStackSupervisor->ActivityManagerService:startProcessLocked()
            end
            ActivityManagerService->ActivityManagerService:startProcessLocked(ProcessRecord app...
            ActivityManagerService->ActivityManagerService:startProcessLocked(String hostingType,...
            ActivityManagerService->ActivityManagerService:startProcess(app.hostingType...
            alt 如果hostingType为webview_service
                ActivityManagerService->Process:startWebView()
            else
                ActivityManagerService->Process:start("android.app.ActivityThread"...)
            end
end

opt startActivity part2
            Process->zygoteProcess:start() 
            zygoteProcess->ActivityThread:...->android.app.ActivityThread main()

            note right of ActivityThread
                Looper.prepareMainLooper();
                ActivityThread thread = new ActivityThread();
                thread.attach(false, startSeq);
                Looper.loop();
            end note
end

Android 10 startActivity 源码分析

Android 10 startActivity 源码分析

源码基于 Android 10

此图着重提炼了生命周期的部分,Android 10 中 新增了 ActivityTaskManager ,专门用于管理 Activity,接替了 ActivityManager 的一部分工作

理解 Instrumentation

Activity 首先会通过 Instrumentation 去调用,Instrumentation 中包含 callActivityOnCreate、callActivityOnPause、callApplicationOnCreate 等调用,具有强大的跟踪 Activity 及 Application 生命周期的功能,所以也被作为应用测试框架中的基类使用。一个进程有一个 ActivityThread 对象,ActivityThread 对象持有一个 Instrumentation 对象,每个 Activity 都持有 Instrumentation

IPC 发生在何处?

在 Instrumentation 中通过 IActivityTaskManager.aidl 接口由 App 进程进入到 system_server 进程;在 ClientTransaction 中通过 IApplicationThread.aidl 接口由 system_server 回到 App 进程

Activity 栈是如何管理的?

ActivityRecord:Activity 以 ActivityRecord 形式记录,一个 ActivityRecord 对应一个 Activity 实例
TaskRecord:这个才是一个真正的 Activity 栈,内部持有 ArrayList< ActivityRecord >,记录当前栈中所有的 Activity
ActivityStack:负责管理 Activity 栈,存放了多个 TaskRecord

何处读取 manifest 中 Activity 节点的启动模式等配置

如图通过 PackageManagerService#resolveIntentInternal 方法返回 ResolveInfo ,ResolveInfo 包括 ActivityInfo、ServiceInfo、ProviderInfo 等信息,此调用已经处于 system_server 进程了,所以并不是 IPC,PackageManagerService 主要负责解析 AndroidManifest.xml、扫描本地 apk 目录、管理 App 安装删除等

何处检测 Activity 是否在 manifest 注册?

关键代码在 ActivityStarter#startActivity 方法中:

       if (err == ActivityManager.START_SUCCESS && aInfo == null) {
           // We Couldn't find the specific class specified in the Intent.
           // Also the end of the line.
           err = ActivityManager.START_CLASS_NOT_FOUND;
       }

aInfo 就是 ActivityInfo ,而 ActivityInfo 为空导致后续报错返回。那 aInfo 是从哪来的呢?当然就是通过 PackageManagerService#resolveIntentInternal 方法解析出来的。然后在 Instrumentation#checkStartActivityResult 方法中检测到 ActivityManager.START_CLASS_NOT_FOUND 返回值后,就抛出 "Unable to find explicit activity class {xxx}; have you declared this activity in your AndroidManifest.xml? "异常了

为什么单独配置 taskAffinity 不会生效

关键代码在 ActivityStarter#startActivityUnchecked 方法中:

  if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
         newTask = true;
         result = setTaskFromreuSEOrCreateNewTask(taskToAffiliate);
  } else if (mSourceRecord != null) {
         result = setTaskFromSourceRecord();
  } else if (mInTask != null) {
         result = setTaskFromInTask();
  } else {
         result = setTaskToCurrentTopOrCreateNewTask();
  }

只有 mLaunchFlags 标记为 FLAG_ACTIVITY_NEW_TASK 才会去创建一个新的 Activity 栈即 TaskRecord,而系统并没有对单独配置一个 taskAffinity 的情况做处理。那在 AndroidManifest.xml 中配置的 launchMode 是在何处处理,并反应到 mLaunchFlags 中的呢?
ActivityStarter#startActivityUnchecked 方法中调用了 ActivityStarter#computeLaunchingTaskFlags 方法,该方法中配置 mLaunchFlags 的代码如下:

   if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && mInTask == null) {
         Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
                        "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
         mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
    }else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
         mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
    } else if (isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
         mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
    }

可以看到 LAUNCH_SINGLE_INSTANCE 模式会在一个新的栈中启动等我们早已熟知的规则

理解 ClientTransactionItem 与 ActivityLifecycleItem

ClientLifecycleManager 可以将一或多个生命周期事件组合到一起作为一个事务即 ClientTransaction 来执行,startActivity 时新 Activity 的 onCreate、onStart、onResume 事件就是存放在一个事务中被执行的

startActivity 时新 Activity 的 onCreate 事件存放在 ClientTransaction 的 List < ClientTransactionItem > 类型的成员变量中,载体为 LaunchActivityItem。 LaunchActivityItem 也是 ClientTransactionItem 的子类,即启动 Activity 事件。另外还有 NewIntentItem(触发 onNewIntent 回调)、ActivityResultItem(触发 onActivityResult)、ConfigurationChangeItem(触发 onConfigurationChanged 回调)等事件

startActivity 时新 Activity 的 onResume 事件存放在 ClientTransaction 的 ActivityLifecycleItem 类型的变量成员变量中,这个变量也表示最终的生命周期状态,载体为 ResumeActivityItem。ActivityLifecycleItem 也是 ClientTransactionItem 的一个子类

为什么不能在 Activity 的 onPause 方法中做耗时操作?

ClientTransaction 为 Parcelable 数据,会通过 IApplicationThread.aidl 的 scheduleTransaction 方法发送到 App 端,然后加入到主线程 ActivityThread.H 消息队列中等待执行。startActivity 时会依次发送前一个 Activity 的 pause 和新 Activity 的 resume 事务,然后这两个事务会通过 ActivityThread.H 依次执行,所以不能在 Activity 的 onPause 方法中做耗时操作,因为只有 onPause 方法执行完后,下一个 Activity 的生命周期事件才能被执行,否则会阻塞新界面显示

activity 实例在何处创建?

在 ActivityThread#performlaunchActivity 方法中,会通过 Instrumentation#newActivity 方法创建 Activity 的实例对象,随后就调用了 Instrumentation#callActivityOnCreate 方法回调 Activity 的 onCreate 方法

Launcher 中点击图标启动 App

Launcher 中点击图标启动同样是调用 startActivity 方法,但需要创建进程,关键代码在 ActivityStackSupervisor#startSpecificActivityLocked 方法中:

   final WindowProcessController wpc =
           mService.getProcessController(r.processName, r.info.applicationInfo.uid);
   if (wpc != null && wpc.hasThread()) {
        //判断进程存在,继续启动
        realStartActivityLocked(r, wpc, andResume, checkConfig);
        return;
   }
   //进程不存在,创建进程
   final Message msg = PooledLambda.obtainMessage(
           ActivityManagerInternal::startProcess, mService.mAmInternal, r.processName,
           r.info.applicationInfo, kNownTobedead, "activity", r.intent.getComponent());
   mService.mH.sendMessage(msg);

与 zygote 进程通信采取了 Socket 方式,为什么不使用更安全、数据只需拷贝一次的 binder 呢?zygote 作为 Android 的受精卵进程,通过 fork 方法创建进程,而 fork 是不允许多线程的,否则会因为 copy-on-Write 机制导致死锁,而 binder 正是基于多线程运行的

在 ProcessList#startProcessLocked 方法中,传入了值为 “android.app.ActivityThread” 的 entryPoint 参数,后续会透传给 zygote 进程,zygote fork 新进程成功后,新进程的 ActivityThread#main 函数会被调用,即 App 真正的启动入口

在 ActivityManagerService#attachApplicationLocked 方法中执行了两个关键逻辑,一是通过 IApplicationThread 回到 App 进程中创建 Application 实例并回调 onCreate 方法;二是调用 ActivityTaskManagerService#attachApplication 方法,进一步去启动首页 Activity 。
启动 Activity 和普通的 startActivity 一样,都会调用到 ActivityStackSupervisor#realStartActivityLocked 方法

理解 ActivityThread 与 ApplicationThread

ActivityThread.main() 方法是程序的启动入口,初始化了主线程 Looper,在 ActivityThread.H 中处理消息。ApplicationThread 是 ActivityThread 的内部类,实现了 IApplicationThread.aidl 接口以接受 AMS 等系统服务的回调,而大多数都是四大组件相关的任务,所以发送 Handler 消息到 ActivityThread.H ,即从 binder 线程切换到主线程中处理

如何启动一个未在 manifest 中注册的 Activity ?

加载 manifest 信息及检测注册在 system_server 进程,即无法干扰检测逻辑。常见做法是在 manifest 中注册一个占位 Activity,在进入 system_server 进程之前把未注册的 Activity 修改为占位 Activity,然后等从 system_server 返回到 App 进程后再修改回未注册的 Activity,然后去创建、启动,也就是说需 hook 两处:

hook ActivityTaskManager:

final Field singletonField = ActivityTaskManager.class
             .getDeclaredField("IActivityTaskManagerSingleton");
singletonField.setAccessible(true);
Singleton singleton = (Singleton) singletonField.get(null);
final Object activityTaskManagerObject = singleton.get();
final Field mInstanceField = Singleton.class.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
Object value = Proxy.newProxyInstance(ActivityTaskManager.class.getClassLoader()
     , new Class[]{Class.forName("android.app.IActivityTaskManager")}
     , new InvocationHandler() {
           @Override
           public Object invoke(Object proxy,
                         Method method, Object[] args) throws Throwable {
              if ("startActivity".equals(method.getName())) {
                  Intent raw;
                  int index = 0;
                  for (int i = 0; i < args.length; i++) {
                     if (args[i] instanceof Intent) {
                        index = I;
                        break;
                     }
                  }
                  if (!(args[index] instanceof Intent)) throw new AssertionError();
                  raw = (Intent) args[index];
                  if (raw.getComponent().getClassName()
                         .equals("com.yinghao.test.UnRegisteractivity")) {
                      ntent newIntent = new Intent();
                      //将未注册的 UnRegisteractivity 替换为占位 FakeActivity
                      newIntent.setComponent(new ComponentName("com.yinghao.test", 
                                   FakeActivity.class.getName()));
                      //记录 UnRegisteractivity
                      newIntent.putExtra(EXTRA_TARGET_INTENT, raw); 
                      args[index] = newIntent;
                  }
              }
              return method.invoke(activityTaskManagerObject, args);
           }
});
mInstanceField.set(singleton, value);

hook ActivityThread:

ActivityThread activityThread = ActivityThread.currentActivityThread();
Field mH1 = activityThread.getClass().getDeclaredField("mH");
mH1.setAccessible(true);
final Handler mH = (Handler) mH1.get(activityThread);
Field mCallBackField = Handler.class.getDeclaredField("mCallback");
mCallBackField.setAccessible(true);
mCallBackField.set(mH, new Handler.Callback() {
 @Override
 public boolean handleMessage(Message msg) {
  try {
   if (msg.what == 159) { // ActivityThread.H.EXECUTE_TRANSACTION
    final ClientTransaction transaction = (ClientTransaction) msg.obj;
    Field mActivityCallbacksField = transaction
               .getClass().getDeclaredField("mActivityCallbacks");
    mActivityCallbacksField.setAccessible(true);
    List<ClientTransactionItem> clientTransactionItems = 
        (List<ClientTransactionItem>) mActivityCallbacksField.get(transaction);
    if (clientTransactionItems != null) {
     for (ClientTransactionItem c : clientTransactionItems) {
      if (c instanceof LaunchActivityItem) {
       //修正 Activity 启动事件实体 LaunchActivityItem
       LaunchActivityItem item = (LaunchActivityItem) c;
       Field intentField = item.getClass().getDeclaredField("mIntent");
       intentField.setAccessible(true);
       Intent intent = (Intent) intentField.get(item);
       Field mInfoField = item.getClass().getDeclaredField("mInfo");
       mInfoField.setAccessible(true);
       ActivityInfo aInfo = (ActivityInfo) mInfoField.get(item);
       Intent realIntent = intent.getParcelableExtra(EXTRA_TARGET_INTENT);
       if (realIntent != null) {
         //将占位 FakeActivity 改回未注册的 UnRegisteractivity
         intent.setComponent(realIntent.getComponent());
         aInfo.packageName = realIntent.getComponent().getPackageName();
         aInfo.name = realIntent.getComponent().getClassName();
       }
       }
     }
    }
   }
  } catch (Exception e) {

  }
  return false; //返回 false 正好可以让 ActivityThread 继续处理
 }
});

实现启动未注册 Activity 的前提必然是已掌握 startActivity 流程,这也是插件化的入门,实际应用需要去兼容各个 Android 版本

最后

带着问题去分析、学习源码,自然的就会聚焦出一条主线

关注公众号,Get 更多知识点

Android SingleTask 和使用 StartActivity(Intent) 似乎调用 onCreate() 方法?

Android SingleTask 和使用 StartActivity(Intent) 似乎调用 onCreate() 方法?

如何解决Android SingleTask 和使用 StartActivity(Intent) 似乎调用 onCreate() 方法?

我的清单文件中定义了两个活动,其中一个是我在单击应用程序中的按钮时启动的活动:

    <activity android:name=".ui.activity.CustomActivity"
        android:launchMode="singleTask"
        />

在我的代码中,我创建了一个意图

startActivity(myIntent)

这将正确启动我的活动,但是当我再次调用该代码时,由于某种原因,它会触发 onCreate 并创建一个新活动,而不是恢复当前活动并为其提供新的意图内容。

有人可以解释为什么它会做出这种行为吗?

解决方法

似乎您需要使用“singleTop”启动模式而不是“singleTask”

今天关于android startactivity 报错android startactivity无效的讲解已经结束,谢谢您的阅读,如果想了解更多关于Ablepsia 和 startActivity() 说再见、AMS startActivity()、Android 10 startActivity 源码分析、Android SingleTask 和使用 StartActivity(Intent) 似乎调用 onCreate() 方法?的相关知识,请在本站搜索。

本文标签: