Отменить (и скрыть) уведомление Android программно - PullRequest
0 голосов
/ 07 января 2019

У меня есть служба, работающая вместе с Уведомлением (Система). Когда служба останавливается (и / или приложение останавливается), уведомление должно быть отменено (т.е. больше не отображается в строке состояния).

Проходя через Руководство по Android-уведомлениям , я не нашел никакой информации о том, как закрыть уведомление.

Переходя к ТАК, я нашел несколько вопросов.

1.

Чтобы подвести итог *1015* *1013* @ nipun.birla, как следует отменить уведомления Android:

К Отменить уведомление , попробуйте по порядку:

  1. NotifcationManager.cancel (int) с notificationID

  2. NotificationManager.cancel (String, int) с notificationID и notificationTag

  3. NotificationManager.cancelAll () как последняя попытка

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

2.

Нужно использовать отменить все предложения

3.

Этот поток SO содержит хороший пример примера запущенной службы с ассоциированным уведомлением, внедренным в жизненный цикл службы (где уведомление также прекращено) - см. Здесь Сведения о запущенной службе

4.

Здесь было предложено удалить PendingIntent , связанное с уведомлением

5.

Еще пара вопросов и решений, отражающих ту же информацию выше: См. это , это и многие другие ...

6.

очень интересный вопрос и решение о программном скрытии значка уведомления в строке состояния


Моя проблема

К настоящему времени это должно быть довольно очевидным , мое уведомление не отменяется само по себе просили сделать это.

Реализация:

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

- Создать уведомление

private Context context;
private NotificationManager notificationManager;
private NotificationChannel notificationChannel;
private NotificationCompat.Builder notificationBuilder;

public NotificationHelper(Context context) {
    this.context = context;

    // Init notification

    // onNotificationCreate()
    {

        // get notification manager system service
        notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // Create notification channel
            createNotificationChannel();

            //Register notification channel with notification manager
            notificationManager.createNotificationChannel(notificationChannel);
        }

    }

    // Init Notification Builder

    // createNotificationChannel() 
    {
        Log.d(TAG, "createNotificationChannel: Creating notification channel");

        // Define notification channel ID, Channel Name and description
        String channelName = BuildConfig.FLAVOR.concat(" Notifier");
        String channelDescription = context.getString(R.string.notification_description);

        // Create notification channel
        notificationChannel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_LOW);
        // Set description of notification channel
        notificationChannel.setDescription(channelDescription);
    }
}

Это вызывается new NotificationHelper(getApplicationContext), где контекстом является Приложение используемый контекст (, который также используется в качестве контекста для многих других функций )

Методология моего вспомогательного класса заключается в простом использовании цепочки методов , позволяющей использовать более eye-candy'ish подход к созданию, изменению и отмене уведомления.

- Использование NotificationHelper:

Настройка уведомлений contentText по телефону setTextContent(String):

public NotificationHelper setTextContent(String text){
    notificationBuilder.setContentText(text);
    return this;
}

установка contentTitle с помощью `setTitle (String):

public NotificationHelper setTitle(String format) {
    notificationBuilder.setContentTitle(format);
    return this;
}

и настройку smallIcon (значок состояния), набрав setStatusIcon(int):

public NotificationHelper setStatusIcon(int res_id) {
    notificationBuilder.setSmallIcon(res_id);
    return this;
}

Наконец, обновление уведомления для отображения результирующих настроек выполняется:

public void update() {
    Log.d(TAG, "update: Updating notification");
    Notification notification = notificationBuilder.build();

    // Set notification flags
    notification.flags |= Notification.FLAG_NO_CLEAR;
    notification.flags |= Notification.FLAG_ONGOING_EVENT;
    notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;

    // Notify update
    notificationManager.notify(TAG, notificationId, notification);
}

- Отменить уведомление

И, как и ожидалось, отменить уведомление так же просто, как позвонить cancelNotification():

public void cancelNotification() {
    Log.d(TAG, "cancelNotification: Cancelling notification");
    notificationManager.cancel(TAG, notificationId);
}

Это, однако, не влияет на отмену уведомления.

Когда уведомление отменено , перед отменой произошло следующее.

  • Выход из приложения запущен.
  • Служба Bound не связана, что гарантирует отсутствие привязки к ней клиентов. unbindService вызывается с getApplicationContext() в контексте владения, например unbindService (ServiceConnection) с использованием того же ServiceConnection , что и изначально связано с.

Сделав все это, уведомление остается.

Что я пробовал

  • notificationManger.cancel(int)
  • notificationManger.cancel(String, int)
  • notificationManger.cancelAll

Это не сработало, поэтому я стал креативным:

Кроме того: Создание отдельного NotificationManager метода для публикации этих обновлений (т. Е. Здесь не установлены флаги, но используется тот же notificationmanager)

public void updateCancelable() {
    Log.d(TAG, "update: Updating notification to cancel");
    Notification notification = notificationBuilder
            .setContentIntent(null)
            .setOngoing(false)
            .setAutoCancel(true)
            .build();
    // Notify update
    notificationManager.notify(TAG, notificationId, notification);
}

Это тоже не помогло. Есть ли что-то, что я могу упустить?

Я должен также упомянуть об этом: во время отладки моего приложения я заметил, что при выходе из приложения (остановив привязанную службу и вызывая cancelNotification(), приложение больше не должно работать, хотя Android Studio делает это). по-прежнему оставляйте активным сеанс отладки открытым, как и следовало ожидать, когда приложение еще работает. Не уверен, что это как-то связано с ним


Класс NotificationHelper (полная реализация)

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

import com.connectedover.BuildConfig;
import com.connectedover.R;
import com.connectedover.listeners.NotificationUpdateListener;

/**
 * Class aimed at providing helper method for creating, maintaining and destroying notifications in conjunction with {@link de.blinkt.openvpn.core.OpenVPNService}
 *
 * @author cybex
 * @since 1.5.1
 */
public class NotificationHelper implements NotificationUpdateListener {

    private static final String TAG = NotificationManager.class.getSimpleName();
    private static final String channelId = BuildConfig.APPLICATION_ID.concat(".").concat(TAG);
    private static final int notificationId = 42;

    private Context context;
    private NotificationManager notificationManager;
    private NotificationChannel notificationChannel;

    private NotificationCompat.Builder notificationBuilder;

    public NotificationHelper(Context context) {
        this.context = context;

        // Init notification
        onNotificationCreate();

        // Init Notification Builder
        createBasicNotification();
    }

    /**
     * Initialize {@link NotificationChannel} and register channel with {@link NotificationManager} service if API is Android Orea (API 26 or higher), else initializes the notification manager
     */
    private void onNotificationCreate() {
        Log.d(TAG, "onNotificationCreate: Initializing notification helper");

        // get notification manager system service
        notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // Create notification channel
            createNotificationChannel();

            //Register notification channel with notification manager
            notificationManager.createNotificationChannel(notificationChannel);
        }
    }

    /**
     * Creates a notification channel required by devices running Android SDK 26 and higher.
     * The notification  channel is set to {@link NotificationManager#IMPORTANCE_LOW} which should have no sound and appear right at the top of the status bar
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    private void createNotificationChannel() {
        Log.d(TAG, "createNotificationChannel: Creating notification channel");

        // Define notification channel ID, Channel Name and description
        String channelName = BuildConfig.FLAVOR.concat(" Notifier");
        String channelDescription = context.getString(R.string.notification_description);

        // Create notification channel
        notificationChannel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_LOW);
        // Set description of notification channel
        notificationChannel.setDescription(channelDescription);
    }

    /**
     * Creates a basic notification using {@link android.support.v4.app.NotificationCompatBuilder} for use throughout the application
     */
    private void createBasicNotification() {
        // Instantiate Notification Builder
        notificationBuilder = new NotificationCompat
                .Builder(context, channelId)
                .setContentTitle(context.getString(R.string.app_name))
                .setSmallIcon(R.drawable.ic_logo_disconnected)
                .setWhen(System.currentTimeMillis())
                .setAutoCancel(false)
                .setOngoing(true);
    }

    /**
     * Set the pending intent of a clickable {@link android.app.Notification} held by {@link NotificationHelper#notificationBuilder}
     * @param pendingIntent Pending intent to connect to activity
     * @return returns an instance of {@link NotificationHelper}
     */
    public NotificationHelper setPendingIntent(PendingIntent pendingIntent){
        Log.d(TAG, "setPendingIntent: Setting notification Pending intent");
        notificationBuilder.setContentIntent(pendingIntent);
        return this;
    }

    /**
     * Updates the notification which is displayed for the user.
     */
    public void update() {
        Log.d(TAG, "update: Updating notification");
        Notification notification = notificationBuilder.build();

        // Set notification flags
        notification.flags |= Notification.FLAG_NO_CLEAR;
        notification.flags |= Notification.FLAG_ONGOING_EVENT;
        notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;

        // Notify update
        notificationManager.notify(TAG, notificationId, notification);
    }

    /**
     * Updates the notification {@link NotificationHelper#notificationBuilder} with new text and displays it to the user
     *
     * @param text new text to display
     * @return returns current {@link NotificationHelper} instance for method chaining.
     */
    public NotificationHelper setTextContent(String text){
        notificationBuilder.setContentText(text);
        return this;
    }

    @Override
    public void onUpdate(String update) {
        Log.d(TAG, "onUpdate: updating notification via callback");
        this.setTextContent(update)
                .update();
    }

    /**
     * Sets a new icon for the notification displayed to the user
     * @param res_id icon resource
     * @return current instance
     */
    public NotificationHelper setLargeIcon(int res_id) {
        notificationBuilder.setLargeIcon(ImageUtils.toBitmap(context, res_id));
        return this;
    }

    /**
     * Sets a new icon for the notification displayed to the user show in the status bar (i.e. the small icon)
     * @param res_id icon resource
     * @return current instance
     */
    public NotificationHelper setStatusIcon(int res_id) {
        notificationBuilder.setSmallIcon(res_id);
        return this;
    }

    public NotificationHelper setTitle(String format) {
        notificationBuilder.setContentTitle(format);
        return this;
    }

    /**
     * Cancels the application notification
     */
    public void cancelNotification() {
        Log.d(TAG, "cancelNotification: Cancelling notification");
        notificationManager.cancelAll();
    }
}

1 Ответ

0 голосов
/ 07 января 2019

Если вы хотите использовать Notification как часть службы переднего плана, а не манипулировать флагами напрямую, используйте startForeground() и stopForeground() на вашем Service.

...