Intent - если активность запущена, переведите ее вперед, иначе запустите новую (из уведомления)

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

Что я хочу сделать, так это принести активность, указанную в ожидающих намерения уведомлениях, на передний план, если она уже запущена, иначе запустите ее.

До сих пор намерение/ожидающее намерения для этого уведомления у меня есть

private static PendingIntent prepareIntent(Context context) {
    Intent intent = new Intent(context, MainActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);

    return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}

и странно, это иногда работает, иногда это не так... Я чувствую, что я уже пробовал каждую комбинацию флагов.

Ответ 1

Вы можете использовать это:

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

который будет работать аналогично "singleInstance", но у него не будет такой странной анимации.

Ответ 2

Я думаю, что лучший способ сделать это и простым способом - начать работу нормально, но установить эту активность в манифесте с помощью свойства singleInstance. При этом вы практически подходите к обоим проблемам, которые у вас есть сейчас, постоянно перенося деятельность на фронт и позволяя ОС автоматически создавать новую, если никакой активности не существует или не вывести на передний план текущую деятельность (благодаря singleInstance).

Так объявляется как один объект:

<activity 
   android:name=".YourActivity"
   android:launchMode="singleInstance"/>

Также, чтобы избежать прерывистой анимации при запуске через singleInstance, вы могли бы использовать вместо этого "singleTask", оба очень похожи, но разница объясняется здесь в соответствии с документацией Google:

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

singleInstance - это то же самое, что и "singleTask", за исключением того, что система не запускает никаких других действий в задачу, пример. Деятельность всегда является единственным и единственным членом ее Задача.

Надеюсь, что это поможет.

Привет!

Ответ 3

Я думаю, что вам нужно singleTop Activity, а не singleTask или singleInstance.

<activity android:name=".MyActivity"
          android:launchMode="singleTop"
          ...the rest... >

Что документация говорит, отлично соответствует вашим потребностям:

[...] может быть создан новый экземпляр действия "singleTop" для обработки новое намерение. Однако, если целевая задача уже имеет экземпляр действия в верхней части его стека, этот экземпляр будет получить новое намерение (в вызове onNewIntent()); новый экземпляр не создано. В других обстоятельствах - например, если существующее экземпляр действия "singleTop" находится в целевой задаче, но не в вершину стека, или если она находится в верхней части стека, но не в target task - новый экземпляр будет создан и помещен в стек.

Вдобавок к этому (каламбур не предназначен), у меня была такая же потребность, как и вы. Я тестировал все флаги launchMode, чтобы выяснить, как они на самом деле ведут себя на практике, и в результате singleTop на самом деле является лучшим для этого: ни одна странная анимация, приложение отображается один раз в списке последних приложений (в отличие от singleInstance, который отображает он дважды из-за того, что он не позволяет другим другим Activity быть частью его задачи), и правильное поведение, независимо от цели Activity уже существует или нет.

Ответ 4

Я знаю, что он старый, но ничего из вышеприведенного не подходит для моего приложения.

Без изменения манифестов и другой конфигурации, вот код, чтобы вернуть ваше приложение назад - или открыть его, когда он закрыт

Intent notificationIntent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
notificationIntent.setPackage(null); // The golden row !!!
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);

Ответ 5

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

intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);

Только API11 +.

Ответ 6

Я пробовал это, и он работал, даже несмотря на то, что IDE жаловался на код

Intent notificationIntent = new Intent(THIS_CONTEXT, MainActivity.class);
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
    PendingIntent intent = PendingIntent.getActivity(THIS_CONTEXT, 0, notificationIntent, Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);

    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(THIS_CONTEXT)
            .setSmallIcon(R.drawable.cast_ic_notification_0)
            .setContentTitle("Title")
            .setContentText("Content")
            .setContentIntent(intent)
            .setPriority(PRIORITY_HIGH) //private static final PRIORITY_HIGH = 5;
            .setAutoCancel(true)
            /*.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_LIGHTS)*/;
    NotificationManager mNotificationManager = (NotificationManager) THIS_CONTEXT.getSystemService(Context.NOTIFICATION_SERVICE);
    mNotificationManager.notify(0, mBuilder.build());

Ответ 7

Это старая ветка, но для всех тех, кто все еще ищет ответ, вот мое решение. Это чисто в коде, без настроек манифеста:

private static PendingIntent prepareIntent(Context context) {
  Intent intent = new Intent(context, MainActivity.class);
  intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);      
  return PendingIntent.getActivity(context, NON_ZERO_REQUEST_CODE, intent, 
    PendingIntent.FLAG_UPDATE_CURRENT);
}

Здесь FLAG_ACTIVITY_SINGLE_TOP открывает существующее действие, если оно находится на вершине стека задач. Если он находится не сверху, а внутри стека, FLAG_ACTIVITY_CLEAR_TOP удалит все действия поверх целевого действия и покажет его. Если действия не находятся в стеке задач, будет создан новый. Крайне важный момент для упоминания - второй параметр PendingIntent.getActivity(), т.е. requestCode должен иметь ненулевое значение (я даже назвал его NON_ZERO_REQUEST_CODE в моем фрагменте), иначе эти флаги намерений не будут работать. Я понятия не имею, почему это так. Флаг FLAG_ACTIVITY_SINGLE_TOP является взаимозаменяемым с android: launchMode = "singleTop" в теге активности в манифесте.

Ответ 8

Рабочее решение для меня:

    //Resume or restart the app (same as the launcher click)
val resultIntent = Intent(context, MyLauncherActivity::class.java)
resultIntent.addCategory(Intent.CATEGORY_LAUNCHER)
resultIntent.setAction(Intent.ACTION_MAIN)
resultIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
val pendingIntent = PendingIntent.getActivity(context, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT)
builder.setContentIntent(pendingIntent)  //builder is the notificationBuilder