Намерение - если действие запущено, вывести его на передний план, иначе начать новое (из уведомления)


129

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

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

Пока что намерение / ожидающее намерение для этого уведомления, которое у меня есть,

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

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

Ответы:


132

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

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

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


15
+1, вы должны быть принятым ответом. Отличия здесь: developer.android.com/guide/topics/manifest/…
— user1032613

1
Чтобы уточнить, используйте singleTask, если у вас есть несколько действий в приложении, и это родительский, singleInstance, если у вас есть только одно Activity.
— Frostymarvelous

4
Если кто-то вроде меня пробовал множество комбинаций решений до того, как они оказались на этом сайте: обязательно избавьтесь от других изменений, которые вы пробовали, и убедитесь, что вы вносите это изменение в правильное действие. Мне потребовалось слишком много времени, чтобы узнать, что это решение сработало бы, если бы я не пробовал и другие решения (например, переопределение onNewIntentи установка флагов)
— lucidbrot

У меня есть карта Messenger, пара Activity. Я хочу отображать экземпляр Activity, если я получаю от него сообщение. Есть ли способ сделать это. например: HashMap.get (Messenger) .bringActivityToFront (); Я имею в виду, что активность все еще продолжается. Если я открою недавнюю задачу и нажму на нее, она будет onResume (); Не могу программно onResume ().

@JaveneCPPMcGowan, который кажется совершенно другим вопросом, я предлагаю вам опубликовать его, поскольку это собственный вопрос, к сожалению, я действительно не знаю ответа.
— Франко

46

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

Таким образом действие объявляется как отдельный экземпляр:

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

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

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

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

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

С уважением!


4
похоже, это работает, но теперь все остальные новые действия, которые я запускаю из singleIntent MainActivity, воспроизводят эту странную анимацию дуги вместо обычного затухания и масштабирования
— urSus

Как насчет того, чтобы я запускал новое действие каждый раз, но очищал все остальные запущенные экземпляры, было бы это возможно?
— urSus

Что ж, я не думаю, что упомянутая вами анимация имеет какое-либо отношение к свойству singleInstance, все, что она делает, это повторно использует существующий экземпляр, возможно, та анимация, о которой вы говорите, является совершенно другой проблемой ...
— Мартин Казарес,

1
ну, я тестирую это прямо сейчас, и это действительно так. Если я удалю все флаги намерений и просто установлю launchMode = "singleInstance" в манифесте, будет странная анимация, если я удалю ее, она вернется в нормальное состояние
— urSus

Да, согласно документации по Android, похоже, что анимация "init" больше не существует, как обычно, потому что активность не инициализируется, а просто повторно используется ...
— Мартин Казарес

26

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

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

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

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

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


2
Работаю до 22:00 в пятницу вечером, и это то, чего я хочу ... Печальная жизнь разработчика.
— felixwcf

Сэкономил много времени! Спасибо!
— hetsgandhi 03

13

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

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" в теге активности в манифесте.


Сражаюсь часами с этими флагами и задавался вопросом, почему изменение моих флагов намерений ничего не изменило. Ненулевой код запроса ... очень важный момент !!! Работает сейчас! Спасибо!
— Max Power

9

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

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

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

Это настоящий ответ!
— azizbekian

2
нет, он не работает - он добавляет новое действие поверх текущего.
— Тоблюг

3

Я попробовал это, и это сработало, хотя среда 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());

2
<активность андроид: имя = "MainActivity." андроид: launchMode = "singleTask">
— нада

Intent.FLAG_ACTIVITY_REORDER_TO_FRONTне является допустимым для флагаPendingINtent.getActivity
— Rds

@rds Можете ли вы связать источник?
— Луи CAD

@LouisCAD Я извиняюсь, у меня нет доступа к исходному коду больше
— нада

@rds Я не прошу исходный код, но ссылка на то место, где вы читаете, Intent.FLAG_ACTIVITY_REORDER_TO_FRONTне является допустимым флагом при использовании в качестве PendingIntent. Или, может быть, вы имели в виду, что это недопустимо для передачи в getActivityметод, но допустимо для использования в качестве Intentфлага, который затем используется как PendingIntent?
— Луи CAD

2

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

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

Только API11 +.


0

У меня была аналогичная проблема после добавления уведомлений, найденных на сайте обучения Android . Ни один из других ответов здесь не сработал для меня, однако этот ответ сработал для меня. Резюме:

final Intent notificationIntent = new Intent(context, YourActivity.class);
notificationIntent.setAction(Intent.ACTION_MAIN);
notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.