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


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

і дивно, що іноді це спрацьовує, іноді - ні. Я відчуваю, що я вже пробував кожну комбінацію прапорів.

Відповіді:


131

Ви можете скористатися цим:

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

яка буде працювати аналогічно, "singleInstance"але у неї не буде такої дивної анімації.


15
+1, вам слід прийняти відповідь. Відмінності тут: developer.android.com/guide/topics/manifest/…
користувач1032613

1
Для уточнення використовуйте singleTask, якщо у вас є кілька дій у додатку, і це батьківський, singleInstance, якщо у вас є лише одна активність.
frostymarvelous

4
Якщо хтось, як я, випробував безліч комбінацій рішень, перш ніж вони опинилися на цьому веб-сайті: Не забудьте позбутися від інших змін, які ви намагалися, і переконайтеся, що ви внесете ці зміни до правильної діяльності. Займав мене занадто довго, щоб дізнатися, що це рішення спрацювало, якби я не спробував і інших рішень (наприклад, onNewIntent
переосмислення

У мене є карта Messenger, пара активності. Я хочу відобразити екземпляр Activity, якщо я отримаю від нього повідомлення. Чи є спосіб це зробити. наприклад: HashMap.get (Messenger) .bringActivityToFront (); Я маю на увазі, діяльність все ще триває. Якщо я відкрию недавнє завдання і натискаю його, він буде onResume (); Cant I 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
це, здається, працює, але тепер кожна інша нова активність, яку я запускаю з єдиного «Інтенційного MainActivity», грає в цю дивну стріляючу анімацію замість регулярного зменшення і масштабування
urSus

Що з того, що я запускав нову діяльність кожного разу, але очищати всі інші запущені екземпляри цього, чи це можливо?
urSus

Ну, я не думаю, що анімація, яку ви згадуєте, не має нічого спільного з властивістю "singleInstance". Все, що вона робить, це повторне використання існуючого екземпляра, можливо, ця анімація, про яку ви говорите, - це зовсім інше питання ...
Мартін Казарес,

1
добре, я тестую це зараз, і це робить. Якщо я видаляю всі прапорці намірів і просто встановлюю в маніфесті запуск startMode = "singleInstance", дивна анімація є, якщо я її
видаляю

Так, згідно з документацією на 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
Працюйте до 10 вечора в п'ятницю ввечері, і ось що я хочу ... Сумне життя розробника.
felixwcf

Врятувало багато мого часу! Дякую!
hetsgandhi

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


З години боюсь із цими прапорами і мені було цікаво, чому зміна моїх прапорців нічого не змінила. Ненульовий код запиту ... надзвичайно важливий момент, який потрібно згадати !!! Працює зараз! Дякую!
Макс. Потужність

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
<активність android: name = ". MainActivity" android: launchMode = "singleTask">
нада

Intent.FLAG_ACTIVITY_REORDER_TO_FRONTне є дійсним прапором дляPendingINtent.getActivity
rds

@rds Чи можете ви зв’язати джерело?
Луї CAD

@LouisCAD Вибачте, у мене більше немає доступу до вихідного коду
nada

@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.