Android LaunchMode and StartActivityForResult

android4.0+已经占据目前主流android系统版本了,在5.0版本发布后,android的LaunchMode与StartActivityForResult的关系发生了一些改变。

两个Activity,A和B,现在由A页面跳转到B页面,看一下LaunchMode与StartActivityForResult之间的关系:

android5.0之前

  stand singleTop singleTask singleInstance
stand x x
singleTop x x
singleTask x x
singleInstance x x x x

android5.0之后

  stand singleTop singleTask singleInstance
stand
singleTop
singleTask
singleInstance

为什么会是这样的呢?

ActivityStackSupervisor类中的startActivityUncheckedLocked方法在5.0中进行了修改。在5.0之前,当启动一个Activity时,系统将首先检查Activity的launchMode,如果为A页面设置为SingleInstance或者B页面设置为singleTask或者singleInstance,则会在LaunchFlags中加入FLAG_ACTIVITY_NEW_TASK标志,而如果含有FLAG_ACTIVITY_NEW_TASK标志的话,onActivityResult将会立即接收到一个cancle的信息。

if (sourceRecord == null) {
    // This activity is not being started from another...  in this
    // case we -always- start a new task.
    if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
        Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
                "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
        launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
    }
} else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
    // The original activity who is starting us is running as a single
    // instance...  this new activity it is starting must go on its
    // own task.
    launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
} else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
        || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
    // The activity being started is a single instance...  it always
    // gets launched into its own task.
    launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
}
// ......
if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
    // For whatever reason this activity is being launched into a new
    // task...  yet the caller has requested a result back.  Well, that
    // is pretty messed up, so instead immediately send back a cancel
    // and let the new task continue launched as normal without a
    // dependency on its originator.
    Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
    r.resultTo.task.stack.sendActivityResultLocked(-1,
            r.resultTo, r.resultWho, r.requestCode,
        Activity.RESULT_CANCELED, null);
    r.resultTo = null;
}

在5.0(含)之后的系统中,对此方法进行了修改:

final boolean launchSingleTop = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP;
final boolean launchSingleInstance = r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE;
final boolean launchSingleTask = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK;
int launchFlags = intent.getFlags();
if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&
        (launchSingleInstance || launchSingleTask)) {
    // We have a conflict between the Intent and the Activity manifest, manifest wins.
    Slog.i(TAG, "Ignoring FLAG_ACTIVITY_NEW_DOCUMENT, launchMode is " +
            "\"singleInstance\" or \"singleTask\"");
    launchFlags &=
            ~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
} else {
    switch (r.info.documentLaunchMode) {
        case ActivityInfo.DOCUMENT_LAUNCH_NONE:
            break;
        case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
            launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
            break;
        case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
            launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
            break;
        case ActivityInfo.DOCUMENT_LAUNCH_NEVER:
            launchFlags &= ~Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
            break;
    }
}
final boolean launchTaskBehind = r.mLaunchTaskBehind
        && !launchSingleTask && !launchSingleInstance
        && (launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0;
if (r.resultTo != null && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
    // For whatever reason this activity is being launched into a new
    // task...  yet the caller has requested a result back.  Well, that
    // is pretty messed up, so instead immediately send back a cancel
    // and let the new task continue launched as normal without a
    // dependency on its originator.
    Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
    r.resultTo.task.stack.sendActivityResultLocked(-1,
            r.resultTo, r.resultWho, r.requestCode,
            Activity.RESULT_CANCELED, null);
    r.resultTo = null;
}

这就解析了为什么5.0(含)之后的系统即便启动的页面设置launchMode为singleTask或singleInstance,onActivityResult依旧可以正常工作。

更多文章请访问小胖轩.

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-10 14:27:34

Android LaunchMode and StartActivityForResult的相关文章

Android基础:startActivityForResult 和 onActivityResult 问题

项目中用到弹出Acitivity来获得用户输入 所以用到 onActivityResult()方法接受用户输入 奇怪问题 startActivityForResult() 后直接调用 onActivityResult()    开发人员都知道,可以通过使用 startActivityForResult() 和 onActivityResult() 方法来传递或接收参数.然而在项目中,还没等到被调用的 Activity 返回,onActivityResult() 就被执行了.找了很久,终于通过小道

android launchMode加载模式和intent flag

ApplicationTask和Process的区别与联系 Application task process 四种加载模式 standard模式 singleTop模式 singleTask模式 singleInstance模式 SingleTask和SingleInstance区别 实例 startActivityForResult如果被启动activity加载模式为SingleTask和SingleInstance 使用Intent标志 FLAG_ACTIVITY_NEW_TASK FLAG

android Intent的startActivityForResult()方法

startActivityForResult() 之前学习了利用Intent跳转页面的同时传值,但有的时候需要从跳转到的页面返回所需要的值(如修改了用户信息,需要返回修改的信息),通俗的意思就是A.Activity跳转到B.Activity,在A.Activity中要自动获取到B.Activity返回的数据. 1.介绍几个主要的方法: 1 MainActivity.this.startActivityForResult(intent1, 1); 第一个参数intent1就不介绍了,第二个参数的值

android launchMode理解以及应用场景

在我们写应用的时候,常常涉及多个activity组件之间的跳转.比如说某个资讯的页面中,点击下一篇资讯跳转相同的页面,只有页面的数据不一样.一般情况下我不会注意launchMode 这个属性,只会使用默认的,这样会产生大量重复的activity.那是因为之前不了解,所以特此研究学习. 1.如何指定launchMode 基本上我们可以直接指定一个launchMode属性在AndroidManifest.xml 文件中 <activity android:name=".views.MainAc

来自Android LaunchMode的温馨提示

西西说 作为一只安卓小白,还是愿意和大家分享我的探索旅程,那么就让我们先来一点来自Android launchMode的温馨提示吧~(≧▽≦)/~. 背景知识 "现在我的手中有一摞牌,但是我让你看到的只有一张." "其他牌去哪了呢?" "其他张牌都被最上面这张牌挡住了呀." 上面的这段话,很形象地解释了acitivity和任务栈的关系. 接下来我们首先了解一下任务--Task. Task Task 是activities的集合,通过back st

android:launchMode概述

android:launchMode An instruction on how the activity should be launched. There are four modes that work in conjunction with activity flags (FLAG_ACTIVITY_* constants) in Intent objects to determine what should happen when the activity is called upon

Android LaunchMode案例篇

首先感谢小伙伴的关注.然后祝愿广大的情侣们节日快乐! 在开发中有时会遇到这种场景,用户点击注冊.第一步,第二步,完毕注冊跳转到登录界面,不须要用户一步一步的返回到登录界面.这是怎么实现的呢? 案例:有四个界面 A.B,C.D 从A跳转到B.B跳转到C,C跳转到D,D完毕注冊跳转到A,点击返回键退出程序.详细过程来看下图: 这里提供了三种常见的解决方式. 方案一 1.清单文件(AndroidManifest.xml)文件设置A的启动模式 <activity android:name=".A&

android launchmode 使用场景

菜鸟起飞记 android launchmode 使用场景 Activity一共有以下四种launchMode: 1.standard 2.singleTop 3.singleTask 4.singleInstance 一,引用场景分析 1.standard 是默认的系统启动模式,每次启动activity都会新建一个实例,也就是说即使启动相同的activity ,他所产生的对象也是不同的. 该种模式大多用于 页面切换的 中间页,每次都是新页面(适用于大多场景). 2.singleTop 单一栈顶

android launchmode(四种启动模式)应用场景及实例

模式介绍 [1] standard 模式 这是默认模式,每次激活Activity时都会创建Activity实例,并放入任务栈中. [2] singleTop 模式 如果在任务的栈顶正好存在该Activity的实例,就重用该实例( 会调用实例的 onNewIntent() ),否则就会创建新的实例并放入栈顶,即使栈中已经存在该Activity的实例,只要不在栈顶,都会创建新的实例. [3] singleTask 模式 如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的 onNew