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

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

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

Ursus
источник

Ответы:

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того, существует ли цель уже или нет.

Shlublu
источник
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);
gattsbr
источник