onActivityResult с launchMode="singleTask"?

Когда вы пытаетесь startActivityForResult за Activity который имеет launchMode="singleTask"; он не вернет никаких значений с onActivityResultи когда вы установите launchMode="standard"; все работает нормально, но системные требования говорят об этом Activity должно быть singleTaskЕсть ли способ решить это?

5 ответов

Решение

Документы 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, вы можете отправить его в эфир, когда какой-либо результат будет доступен. Вызывающая активность может затем перечислить эту трансляцию.

Ответ показывает в функции startActivityUncheckedLocked класса ActivityStackSupervisor, До запуска Android 5.x при запуске действия он сначала проверяет режим запуска и добавляет FLAG_ACTIVITY_NEW_TASK для запуска флагов, если launchMode это singleTask или singleInstance. Если 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 singleTask или же singleInstance,

Что говорит @Peter Knego

плюс

похоже, работает в 5.1, а не в 4.4.4

это означает, что срабатывает onActivityResult

Чтобы уточнить некоторые ответы:

API < Android 5.x:

в сочетании с режимами запуска или не работает. onActivityResult()будет вызван немедленно с кодом результата Activity.RESULT_CANCELED.

API >= Android 5.x:

startActivityForResult()работает, но запускает мод singleTaskили singleInstanceв основном игнорируются, то есть активность запускается в той же задаче, и новая задача не создается .

Если вы хотите проверить этот запуск adb shell dumpsys activity activities. Я только хочу, чтобы система, по крайней мере, показала мне предупреждение об этом.

Это изменение также отражено в фрагментах кода, опубликованных @GGCoke .

Я знаю, что уже довольно поздно, но вы можете оказывать влияние OnActivityResult на метод onNewIntent(), потому что это ваше действие в однозадачном режиме.

Другие вопросы по тегам