Ответ 1
Вы можете использовать это:
<activity
android:name=".YourActivity"
android:launchMode="singleTask"/>
который будет работать аналогично "singleInstance"
, но у него не будет такой странной анимации.
В моем приложении есть уведомления, которые, очевидно, без каких-либо флагов, запускают новое действие каждый раз, поэтому я получаю несколько одинаковых действий, выполняющихся поверх друг друга, что просто неправильно.
Что я хочу сделать, так это принести активность, указанную в ожидающих намерения уведомлениях, на передний план, если она уже запущена, иначе запустите ее.
До сих пор намерение/ожидающее намерения для этого уведомления у меня есть
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);
}
и странно, это иногда работает, иногда это не так... Я чувствую, что я уже пробовал каждую комбинацию флагов.
Вы можете использовать это:
<activity
android:name=".YourActivity"
android:launchMode="singleTask"/>
который будет работать аналогично "singleInstance"
, но у него не будет такой странной анимации.
Я думаю, что лучший способ сделать это и простым способом - начать работу нормально, но установить эту активность в манифесте с помощью свойства singleInstance
. При этом вы практически подходите к обоим проблемам, которые у вас есть сейчас, постоянно перенося деятельность на фронт и позволяя ОС автоматически создавать новую, если никакой активности не существует или не вывести на передний план текущую деятельность (благодаря singleInstance
).
Так объявляется как один объект:
<activity
android:name=".YourActivity"
android:launchMode="singleInstance"/>
Также, чтобы избежать прерывистой анимации при запуске через singleInstance, вы могли бы использовать вместо этого "singleTask", оба очень похожи, но разница объясняется здесь в соответствии с документацией Google:
<activity
android:name=".YourActivity"
android:launchMode="singleTask"/>
singleInstance - это то же самое, что и "singleTask", за исключением того, что система не запускает никаких других действий в задачу, пример. Деятельность всегда является единственным и единственным членом ее Задача.
Надеюсь, что это поможет.
Привет!
Я думаю, что вам нужно singleTop
Activity
, а не singleTask
или singleInstance
.
<activity android:name=".MyActivity"
android:launchMode="singleTop"
...the rest... >
Что документация говорит, отлично соответствует вашим потребностям:
[...] может быть создан новый экземпляр действия "
singleTop
" для обработки новое намерение. Однако, если целевая задача уже имеет экземпляр действия в верхней части его стека, этот экземпляр будет получить новое намерение (в вызовеonNewIntent()
); новый экземпляр не создано. В других обстоятельствах - например, если существующее экземпляр действия "singleTop
" находится в целевой задаче, но не в вершину стека, или если она находится в верхней части стека, но не в target task - новый экземпляр будет создан и помещен в стек.
Вдобавок к этому (каламбур не предназначен), у меня была такая же потребность, как и вы. Я тестировал все флаги launchMode
, чтобы выяснить, как они на самом деле ведут себя на практике, и в результате singleTop
на самом деле является лучшим для этого: ни одна странная анимация, приложение отображается один раз в списке последних приложений (в отличие от singleInstance
, который отображает он дважды из-за того, что он не позволяет другим другим Activity
быть частью его задачи), и правильное поведение, независимо от цели Activity
уже существует или нет.
Я знаю, что он старый, но ничего из вышеприведенного не подходит для моего приложения.
Без изменения манифестов и другой конфигурации, вот код, чтобы вернуть ваше приложение назад - или открыть его, когда он закрыт
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);
Поскольку вы говорите, что хотите начать свою деятельность, если она не началась, возможно, вы не возражаете перезапустить ее. Я тестировал массу предложений и комбинаций флагов для намерения, это всегда приведет к активности, которая вам нужна на фронт, хотя она не будет поддерживать какое-либо состояние, ранее связанное с ней.
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);
Только API11 +.
Я пробовал это, и он работал, даже несмотря на то, что 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());
Это старая ветка, но для всех тех, кто все еще ищет ответ, вот мое решение. Это чисто в коде, без настроек манифеста:
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" в теге активности в манифесте.
Рабочее решение для меня:
//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