Android - Открытый флаг задачи не работает для PendingIntent

У меня есть стек задач A > B > C. В настоящее время я на C, а затем нажимаю кнопку "домой". Я получаю уведомление с намерением довести меня до Activity A. Я нажимаю уведомление, и я нахожусь в A, но если я вернусь, я перейду на C, затем B, затем A.

Я настраиваю свой PendingIntent так. Что-нибудь явно не так с этим?

final Intent notificationIntent = new Intent(mContext, ActivityA.class);
        notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);


        PendingIntent contentIntent = PendingIntent.getActivity(myContext, 0, notificationIntent, 0);

РЕДАКТИРОВАТЬ 1:

Я попробовал следующее предложение: Очистить все действия в задаче?

notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);

но я все равно получаю тот же результат. Моя активность A начинается в стеке задач приложения, я отжимаю и перехожу на C, затем B, затем снова A.

Я начинаю думать, что это невозможно в Android или это невозможно при использовании ожидающего намерения.

ИЗМЕНИТЬ 2: Это не вопрос того, какие флаги нужны. Больше вопроса о том, что может быть неправильным, что флаги, кажется, не имеют никакого эффекта.

Ответ 1

если u r с помощью решения 1, то просто удалите launchMode="singleTask" из манифеста

1)

 final Intent notificationIntent = new Intent(mContext, ActivityA.class);

 notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);

 PendingIntent contentIntent = PendingIntent.getActivity(myContext, 0, notificationIntent, 0);

ИЛИ

2)

       <activity 
       android:name=".ActivityA" 
       android:theme="@style/theme_noActionBar" 
       android:noHistory="true">

ИЛИ

3)

<activity android:name=".ActivityA" android:launchMode="singleTop">

Ответ 2

Проблема, с которой вы сталкиваетесь, связана с тем, что Android создает новое задание с использованием вашего PendingIntent и требуемого Intent.FLAG_ACTIVITY_NEW_TASK. Другими словами, флаги, которые вы хотите использовать, имеют отношение к запуску действий в контексте заданного стека задач. У PendingIntent обычно нет контекста, и поэтому то, что вы видите, является задачей, создаваемой для вашего ожидающего намерения Действия.

Вот ссылка на документы:

Android PendingIntent

Требование для первого в серии PendingIntent иметь Intent.FLAG_ACTIVITY_NEW_TASK является проблемой. Обратите внимание, что ряд ожидающих намерений может иметь тот же контекст, что и исходное ожидающее намерение, используя метод "getActivities".

Вы правы, что не возможно делать то, что вы хотите, только используя флаги. Ваш код верен, и для того, чтобы получить желаемое поведение, вам нужно смотреть за пределы намеренных флагов.

Есть много других способов, таких как использование манифеста, запуск службы, использование статических полей и т.д., Чтобы попытаться управлять тем, что вам интересно. Кроме того, вы можете использовать TaskStackBuilder для решения вашей проблемы, если решите пойти по пути использования манифеста. Есть также много других решений, не связанных с флагами, но вы специально спросили об использовании флагов.

Ответ 3

Вы можете установить launchMode ActivityA на singleTask в файле манифеста. Поскольку ActivityA является корнем вашего приложения, он работает.

Из документация:

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

        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:launchMode="singleTask" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

РЕДАКТИРОВАТЬ 1:

Поскольку вы не хотите изменять файл манифеста, только вариант, который я вижу, использует метод Intent.makeRestartActivityTask для генерации намерения. Однако это приведет к возобновлению ActivityA, а не к возобновлению существующего экземпляра.

Intent intent = Intent.makeRestartActivityTask(new ComponentName(this, ActivityA.class));
PendingIntent rIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, 0);

Ответ 4

Решение в терминах флага намерения будет следующим:

  • В манифесте добавьте launchMode:singleTask для операции A
  • Используйте следующий блок кода:

    final Intent notificationIntent = new Intent(mContext, ActivityA.class);
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    PendingIntent contentIntent = PendingIntent.getActivity(myContext, 0, notificationIntent, 0);
    

Что происходит, так это то, что, когда действие A запускается с использованием уведомления, по определению Intent.FLAG_ACTIVITY_NEW_TASK, так как существует задача A > B > C, содержащая A, эта задача выдвигается также, разрушая действия B и C и A начинается с onNewIntent --> onRestart --> onStart --> onResume

Если задача уже запущена для текущей активности, эта задача выводится на передний план с восстановленным последним состоянием, и действие получает новое намерение в onNewIntent()

Теперь причина, почему он не ведет себя хорошо с помощью только флагов намерения, заключается в том, что Activity A не запускался с режимом singleTask, и Android каким-то образом не поддерживает его состояние.

Ответ 5

У меня было много проблем с этим, и я думал, что сошел с ума, пока не удалил/не переустановил мое приложение и не использовал его, этот код работает как много сообщений в Stack Overflow. Я делал следующее:

Intent i = new Intent(getApplicationContext(), MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);

PendingIntent pi = PendingIntent.getActivity(this, 0, i, 0);

и постоянно получал две версии приложения. После удаления на одном устройстве и повторного запуска другого устройства все теперь ведет себя так, как ожидалось, с одним экземпляром. Надеюсь, это поможет вам.

Ответ 6

Попробуйте использовать флаг Intent FLAG_ACTIVITY_CLEAR_TOP вместо очистки задачи. Из Документация о намерениях:

Если установлено, и запущенная деятельность уже запущена в текущей задачи, то вместо запуска нового экземпляра этого деятельность, все другие мероприятия поверх нее будут закрыты и это намерение будет передано (сейчас сверху) старой деятельности как новое намерение.

Например, рассмотрим задачу, состоящую из действий: A, B, C, D. Если D вызывает startActivity() с намерением, который разрешает компонент активности B, то C и D будут завершены и B получит данное намерение, в результате чего стек теперь составляет: A, B.

Ответ 7

Я создал демо-проект в качестве вашего описания, и он работает так же, как и вы.

Я не знаю, как вы получаете уведомление, поэтому в моем проекте я использую BroadcastReceiver для получения широковещательной передачи, а затем показываю уведомление в методе onReceive() получателя. Я думаю, вы можете сравнить мою демонстрацию с вашим проектом, чтобы найти проблему. BTW, мой тест выполняется в соответствии с API 16.

Вот моя демонстрация: https://github.com/leoguo123/AndroidDemo

В репозитории:

Тестовый проект содержит 3 действия (A > B > C), и он может отображать уведомление при получении правильной трансляции. Проект SendBroadcast отвечает за отправку широковещательной передачи.

Код для генерации уведомления:

    public class MyBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        showNotification(context);
    }

    private void showNotification(Context context) {
        Intent intent = new Intent(context, ActivityA.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
                | Intent.FLAG_ACTIVITY_SINGLE_TOP
                | Intent.FLAG_ACTIVITY_NEW_TASK);
        NotificationManager nmr = (NotificationManager) context
                .getSystemService(Context.NOTIFICATION_SERVICE);
        PendingIntent pi = PendingIntent.getActivity(context, 0, intent, 0);
        Notification.Builder builder = new Notification.Builder(context);
        builder.setContentTitle("Open A with B and C being closed");
        builder.setContentText("Open A with B and C being closed");
        builder.setSmallIcon(R.drawable.ic_launcher);
        builder.setContentIntent(pi);
        builder.setAutoCancel(true);
        Notification nt = builder.build();
        nmr.notify(0, nt);
    }
}

Ответ 8

Мой код решения:

    public class MyApplication extends Application{
    private static int activityCounter;
    public Activity A,B,C;
    public void incrementActivityCounter()
    {
        activityCounter++;
    }
    public void decrementActivityCounter()
    {
        activityCounter--;
        if (activityCounter == 0)
        {
            A.finish();
            B.finish();
            C.finish();
        }
    }
}


public class A extends Activity{
   @Override
    protected void onStart()
    {
        super.onStart();
        application.incrementActivityCounter();
    }

    @Override
    protected void onStop()
    {
        application.decrementActivityCounter();
        super.onStop();
    }
}

Ответ 9

Перепробовал все предложения сверху и потерпел неудачу, и пришло решение из руководства из fooobar.com/info/44971/... и fooobar.com/info/1561013/.... Добавлены следующие 2 строки в манифест

android:launchMode="singleTask"
android:clearTaskOnLaunch="true"

и установите PendingIntent в NotificationCompat.Builder, используя

mBuilder.setContentIntent(addBackStack(mContext,intent));

где

public static PendingIntent addBackStack(final Context context, final Intent intent) {
    TaskStackBuilder stackBuilder = TaskStackBuilder.create (context.getApplicationContext ());
    stackBuilder.addNextIntentWithParentStack (intent);
    intent.addFlags (Intent.FLAG_ACTIVITY_NEW_TASK);
    return stackBuilder.getPendingIntent (0,PendingIntent.FLAG_UPDATE_CURRENT);
}

Надеюсь, кому-то поможет.