Як відхилити сповіщення після натискання на дію


143

Оскільки рівень API 16 (Jelly Bean), є можливість додати дії до сповіщення за допомогою

builder.addAction(iconId, title, intent);

Але коли я додаю дію до сповіщення і натискання на дію, повідомлення не відхиляється. Коли натискається саме сповіщення, його можна відхилити

notification.flags = Notification.FLAG_AUTO_CANCEL;

або

builder.setAutoCancel(true);

Але очевидно, це не має нічого спільного з діями, пов’язаними з повідомленням.

Якісь підказки? Або це ще не частина API? Я нічого не знайшов.

Відповіді:


155

Коли ви зателефонували сповістити менеджеру сповіщень, ви надали йому ідентифікатор - це єдиний ідентифікатор, з яким ви можете пізніше отримати доступ до нього (це від менеджера повідомлень:

notify(int id, Notification notification)

Щоб скасувати, вам потрібно зателефонувати:

cancel(int id)

з тим самим ід. Отже, в основному, вам слід відстежувати ідентифікатор або, можливо, помістити його в пакет, який ви додаєте до наміру всередині PendingIntent?


25
Дякую, що вирішив моє питання. Однак я все ще думаю, що це трохи надмірно складно. Замість того, щоб просто надавати API для автоматичного відхилення сповіщення при натисканні на дію, вам потрібно працювати з наміром і передачею ідентифікатора сповіщення, щоб досягти цього.
endowzoner

2
Якщо ви вважаєте, що це складно, не намагайтеся оновлювати сповіщення (не втрачайте цей ідентифікатор) або не перевіряйте, відображається воно чи ні (api не відстежує його, вам доведеться) ...: P
Тревіс

2
@Daksh: В основному, ви додаєте тег та ідентифікатор сповіщень до свого наміру, який починається після натискання вашої дії. За допомогою цієї додаткової інформації ви можете перевірити в початковій діяльності, чи було це розпочато через дію сповіщення.
ендовзонер

5
Зразок коду від onCreate (): додаткові додатки = getIntent (). GetExtras (); if (extras! = null) {String tag = extras.getString (NotificationReceiver.INTENT_EXTRA_NOTIFICATION_TAG); int id = extras.getInt (NotificationReceiver.INTENT_EXTRA_NOTIFICATION_ID); якщо (NotificationReceiver.NOTIFICATION_ID == id && NotificationReceiver.NOTIFICATION_TAG.equals (тег)) ​​{// діяльність розпочато через дії сповіщення, відхилити // сповіщення NotificationManager manager = (NotificationManager) getSystemService (Service.NOTIFICATION_SERVICE); manager.cancel (тег, ідентифікатор); }}
ендовзонер

1
У новому API ви маєте сповіщення (String tag, int id, Notification message) і відповідно скасовуєте (String tag, int id)
Malachiasz

64

Виявив, що це проблема під час використання повідомлення Lollipop Heads Up Display. Див. Рекомендації щодо дизайну . Ось повний (ish) код для реалізації.

Досі мати кнопку "Відхилити" була менш важливою, але тепер це більше перед вами.

очолює повідомлення

Побудова повідомлення

int notificationId = new Random().nextInt(); // just use a counter in some util class...
PendingIntent dismissIntent = NotificationActivity.getDismissIntent(notificationId, context);

NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setPriority(NotificationCompat.PRIORITY_MAX) //HIGH, MAX, FULL_SCREEN and setDefaults(Notification.DEFAULT_ALL) will make it a Heads Up Display Style
        .setDefaults(Notification.DEFAULT_ALL) // also requires VIBRATE permission
        .setSmallIcon(R.drawable.ic_action_refresh) // Required!
        .setContentTitle("Message from test")
        .setContentText("message")
        .setAutoCancel(true)
        .addAction(R.drawable.ic_action_cancel, "Dismiss", dismissIntent)
        .addAction(R.drawable.ic_action_boom, "Action!", someOtherPendingIntent);

// Gets an instance of the NotificationManager service
NotificationManager notifyMgr = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

// Builds the notification and issues it.
notifyMgr.notify(notificationId, builder.build());

NotificationActivity

public class NotificationActivity extends Activity {

    public static final String NOTIFICATION_ID = "NOTIFICATION_ID";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        manager.cancel(getIntent().getIntExtra(NOTIFICATION_ID, -1));
        finish(); // since finish() is called in onCreate(), onDestroy() will be called immediately
    }

    public static PendingIntent getDismissIntent(int notificationId, Context context) {
        Intent intent = new Intent(context, NotificationActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        intent.putExtra(NOTIFICATION_ID, notificationId);
        PendingIntent dismissIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        return dismissIntent;
    }

}

AndroidManifest.xml (атрибути, необхідні для того, щоб SystemUI не сфокусувався на задній стеці)

<activity
    android:name=".NotificationActivity"
    android:taskAffinity=""
    android:excludeFromRecents="true">
</activity>

У мене є декілька сповіщень від однієї програми, і повідомлення прореагує на постійне сповіщення Я хочу очистити сповіщення, коли додавання виконується на пертикулярне сповіщення
Prasad

3
Чи не було б ефективнішим використовувати тут BroadcastReceiver, щоб замість цього відхилити сповіщення? Ось хороший приклад , який показує реалізацію, але вона може бути ще більше урізані: stackoverflow.com/a/19745745/793150
alice.harrison

1
Рішення працює, за винятком набору додаткових даних, які передаються з наміром. Вони не пересилаються на створення. Один із способів - використання статичних змінних. Хтось знає, чому додаткові наміри не пересилаються?
Бащі

Чому getDismissIntent працює лише тоді, коли він розміщений у NotificationActivity? Намір відхилення не працює, якщо код створення PendingIntent розміщується в класі конструктора сповіщень. Я щойно витратив на це питання 2 години, і я не можу зрозуміти, чому В ході діяльності ОБОВ'ЯЗКОВО повинен бути створений намір. Хтось може пояснити, чому це так?
Рей Лі

getDismissIntent () - статична функція "помічник", яка створює правильний Намір, який використовується для спілкування з NotificationActivity. Як такі, вони зазвичай входять до діяльності. Але я не бачу, чому цю статичну функцію не можна було розмістити в класі конструктора сповіщень, якщо ви обережно правильно встановили NOTIFICATION_ID та контекст.
Майк

17

Я виявив, що коли ви використовуєте кнопки дій у розширених сповіщеннях, вам потрібно написати додатковий код, і ви більше обмежені.

Вам потрібно вручну скасувати своє повідомлення, коли користувач натисне кнопку дії. Повідомлення скасовується автоматично лише для дії за замовчуванням.

Крім того, якщо ви запускаєте транслятор трансляції з кнопки, ящик сповіщень не закриється.

Я врешті створив нову NotificationActivity для вирішення цих проблем. Ця посередницька діяльність без будь-якого інтерфейсу скасовує сповіщення, а потім починає діяльність, яку я дуже хотів розпочати з повідомлення.

Я опублікував зразок коду в пов’язаній публікації. Натискання дій з повідомленням про Android не закриває ящик повідомлень .


2
Шкода, що вони все ще не вклали це в API ... Це досить хакітно, щоб зробити це так. Але все-таки єдиний спосіб, особливо якщо ви не маєте ніякого контролю над наміром призначення, як-от перегляд URL-адреси.
Богдан Зурак

Дякую за інформацію, ви маєте рацію. Однак я б скоріше скоріше використовував службу, а не посередницьку діяльність
Тім,

7

Ви можете завжди від того, що в даний час викликається дією (наприклад, в діяльності , прив'язаною до вам постачати ).cancel()NotificationonCreate()PendingIntentaddAction()


2
Але як я можу отримати доступ до сповіщення про діяльність, яку називають?
endowzoner

@FleshWound: cancel()приймає ідентифікатор Notification, який ви використовували під час дзвінка notify(). Вам не потрібен Notificationоб’єкт.
CommonsWare

@CommonsWare Скасувати (id) припинив роботу, якщо встановлено setGroup і є підсумкове повідомлення групи. У цьому випадку скасування чомусь нічого не робить. Без резюме групи, хоч скасування працює добре
Кушань

якщо мій очікуваний намір є, ACTION_VIEWа тип - image/jpeg(поділитися зображенням з іншим додатком), то як слід скасувати це скасування? IMO Android повинен автоматично скасувати, я здивований, чому Android просто не піклується про це ?!
Хтось десь

@SomeoneSomewhere: "Тоді як має бути запущене це скасування?" - не може. Хоча ніщо не заважає вам вказувати на сторонній додаток у Notificationпов’язаному відношенні PendingIntent, це не зовсім так, як воно було створено для роботи, і тому ви зіткнетеся з такими проблемами. "IMO Android повинен автоматично скасувати" - я міг бачити, як пропонують прапор для цього в дії, але це не повинно бути річчю все-таки. Якби це було, пропуск композиції в музичному плеєрі сповіщення закрив би сповіщення.
CommonsWare

7

На мою думку, використання A BroadcastReceiver- це більш чистий спосіб скасувати Повідомлення:

В AndroidManifest.xml:

<receiver 
    android:name=.NotificationCancelReceiver" >
    <intent-filter android:priority="999" >
         <action android:name="com.example.cancel" />
    </intent-filter>
</receiver>

Файл у java:

Intent cancel = new Intent("com.example.cancel");
PendingIntent cancelP = PendingIntent.getBroadcast(context, 0, cancel, PendingIntent.FLAG_CANCEL_CURRENT);

NotificationCompat.Action actions[] = new NotificationCompat.Action[1];

NotificationCancelReceiver

public class NotificationCancelReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //Cancel your ongoing Notification
    };
}

1
Це те, що я роблю, але як отримати ідентифікатор сповіщення (у цьому прикладі 0) від методу onReceive? Це не в Намір, оскільки до нього не додано. Я спробував додати його як додатковий, але, схоже, справжній ідентифікатор сповіщення - це не той, який я додавав як додатковий у створенні діяльності ...: - /
Marco Zanetti

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

Але мені довелося використовувати <intent.setAction (Integer.toString (notifikacijaId));> при призначенні, щоб мати змогу відхилити будь-яке показане сповіщення.
Крістоф Мойн

1
@MarcoZanetti вам потрібно створити ідентифікатор сповіщення, який ви перейдете до очікуваного наміру, а також до способу сповіщення під час надсилання повідомлення. Якщо ви це зробите, тоді, коли користувач натисне дії, щоб скасувати, він зателефонує в ефір приймача, і тоді ви можете отримати ідентифікатор сповіщення від додаткових.
Рей Хантер

@ChristopheMoine ви можете поставити ідентифікатор via intent.putExtra() і отримати йогоBroadcastReceiver
Вадим Котов

5

У нових API не забудьте про TAG:

notify(String tag, int id, Notification notification)

і відповідно

cancel(String tag, int id) 

замість:

cancel(int id)

https://developer.android.com/reference/android/app/NotificationManager


Ви були праві! хоча cancel()функція має 2 реалізації; один з TAG і один без. Але ми повинні надати TAG. Ось cancelфункція від docs public void cancel(@Nullable String tag, int id). Востаннє перевірено на Android Q
sud007

1

Просто поставте цей рядок:

 builder.setAutoCancel(true);

Повний код:

NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
    builder.setSmallIcon(android.R.drawable.ic_dialog_alert);
    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.co.in/"));
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
    builder.setContentIntent(pendingIntent);
    builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.misti_ic));
    builder.setContentTitle("Notifications Title");
    builder.setContentText("Your notification content here.");
    builder.setSubText("Tap to view the website.");
    Toast.makeText(getApplicationContext(), "The notification has been created!!", Toast.LENGTH_LONG).show();

    NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    builder.setAutoCancel(true);
    // Will display the notification in the notification bar
    notificationManager.notify(1, builder.build());

AutoCancel, начебто, не впливає при націлюванні на Android 9 (добре працює при
Alix

відмінність тут у дії
Хтось десь

0

Після видалення вашого наміру видалити сповіщення вам потрібно буде запустити наступний код.

NotificationManagerCompat.from(this).cancel(null, notificationId);

Примітка: notificationId - це той самий ідентифікатор, що передається для запуску сповіщення


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.