以编程方式取消(并隐藏)Android 通知

Cancel (and hide) Android notification programmatically

我有一项服务 运行 与通知(系统)结合使用。当服务停止时(and/or 应用程序停止),通知应该被取消(即不再显示在状态栏上)。

通过提供 Android Dev guide of Notifications,我没有找到任何关于如何关闭通知的信息。

转到SO,我发现了很多问题。

1.

总结 @nipun.birla's 应该如何取消 Android 通知:

取消通知,请按顺序尝试:

  1. NotifcationManager.cancel(int)notificationID

  2. NotificationManager.cancel(String, int)notificationIDnotificationTag

  3. NotificationManager.cancelAll()作为最后的尝试

但没有提到的是,如果 none 这些工作应该做什么。

2.

应该使用

3.

contains a good example of a Started Service example with an associate notification implemented into the service lifecycle (where the notification is also killed) - See here for Started Service details

4.

a suggestion was made to delete the PendingIntent 与通知关联

5.

反映上述相同信息的更多问题和解决方案: 查看 this, and ,以及更多...

6.

关于以编程方式在状态栏中隐藏通知图标的


我的问题

现在应该很明显了,我的通知并没有取消自己要求这样做。

实施:

请参阅下面的完整实现,尽管我会 post 帮助程序 class 和核心功能的一般用法

- 创建通知

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) 调用,其中上下文是使用的 Application 上下文(它也用作许多其他函数的上下文

我的助手 class 背后的方法是简单地使用 method chaining 允许更 eye-candy'ish 方法来创建、修改和取消一个通知。

- NotificationHelper 用法:

设置通知 contentText 通过调用 setTextContent(String):

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

通过 `setTitle(String):

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

并通过调用 setStatusIcon(int):

设置 smallIcon(状态图标)
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);
}

但这对取消通知没有影响。

取消通知后,在取消之前发生了以下情况。

完成所有这些后,通知仍然存在。

我尝试了什么

这个不行,所以我有创意:

此外: 为 post 这些更新创建一个单独的 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 仍然保持活跃的调试会话打开,就像人们期望的那样,当应用程序仍然 running.Not 确定这是否与它有关


NotificationHelper class(完整实现)

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

如果您想将 Notification 用作前台服务的一部分,而不是直接操作标志,请在 Service 上使用 startForeground()stopForeground()