【问题标题】:onActivityResult With launchMode="singleTask"?onActivityResult 与 launchMode="singleTask"?
【发布时间】:2012-02-16 02:52:55
【问题描述】:

当您尝试使用startActivityForResult 获取具有launchMode="singleTask"Activity 时;它不会返回任何带有onActivityResult 的值,并且当您设置launchMode="standard" 时;一切正常,但系统要求说这个Activity 必须是singleTask,有没有办法解决这个问题?

【问题讨论】:

    标签: android android-activity


    【解决方案1】:

    startActivityForResult 的文档说:

    For example, if the activity you are launching uses the singleTask launch mode,
    it will not run in your task and thus you will immediately receive a cancel result.
    

    似乎没有办法解决这个问题。

    如果您是被调用 Activity 的开发者,那么您可以让它在某些结果可用时发送广播。然后调用的 Activity 可以列出这个广播。

    【讨论】:

    • 那么如何防止在 onClick 中创建多个实例(例如列表视图)?
    【解决方案2】:

    答案显示在 ActivityStackSupervisor 类的函数 startActivityUncheckedLocked 中。 在Android 5.x之前,启动一个activity时,会先检查launchMode,如果launchMode是singleTask或者singleInstance,会在launchFlags中加上FLAG_ACTIVITY_NEW_TASK。如果活动的launchFlags 包含FLAG_ACTIVITY_NEW_TASK,它会立即发回一个取消,让新任务继续正常启动,而不依赖于它的发起者。

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

    但在 Android 5.x 中,更改如下:

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

    这就是为什么 onActivityResult 可以在 Android 5.x 中运行,即使您将 launchMode 设置为 singleTasksingleInstance

    【讨论】:

      【解决方案3】:

      @Peter Knego 怎么说

      它似乎在 5.1 中工作,而不是在 4.4.4

      表示 onActivityResult 触发

      【讨论】:

      • 是的,我还观察到它在 5.o 及更高版本中工作,而不是在 4.4.4 中
      【解决方案4】:

      澄清一些答案:

      API 的

      startActivityForResult() 与启动模式 singleTasksingleInstance 结合使用不起作用。 onActivityResult() 将立即被调用,结果代码为Activity.RESULT_CANCELED

      API 的 >= Android 5.x:

      startActivityForResult() 有效,但启动模式singleTasksingleInstance 基本上被忽略,这意味着活动被启动到同一个任务中并且没有创建新任务

      如果你想验证这个运行adb shell dumpsys activity activities。我只希望系统至少会向我显示一个警告。

      这种变化也反映在@GGCoke 的代码位中有posted

      【讨论】:

        【解决方案5】:

        我知道这已经很晚了,但您可以对 onNewIntent() 方法产生 OnActivityResult 效果,因为这是您的 singleTask 活动。

        【讨论】:

          猜你喜欢
          • 2014-11-04
          • 1970-01-01
          • 1970-01-01
          • 2015-12-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-03-26
          • 1970-01-01
          相关资源
          最近更新 更多