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

KGC*_*beX 5 notifications android android-service notificationmanager android-notifications

我有一个与通知(系统)一起运行的服务。当服务停止(和/或应用程序停止)时,应取消通知(即不再显示在状态栏上)。

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

去SO,我发现了一些问题。

1.

总结@nipun.birla对如何取消 Android 通知的回答

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

  1. NotifcationManager.cancel(int)notificationID

  2. NotificationManager.cancel(字符串,整数)notificationIDnotificationTag

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

但是没有提到的是,如果这些都不起作用,应该怎么做。

2.

一个应该使用cancelAll建议

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这被调用,new NotificationHelper(getApplicationContext)其中上下文是使用的应用程序上下文(它也用作许多其他函数的上下文

我的助手类背后的方法是简单地使用方法链,允许使用更吸引人的方法来创建、修改和取消通知。

- NotificationHelper 用法:

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

public NotificationHelper setTextContent(String text){
    notificationBuilder.setContentText(text);
    return this;
}
Run Code Online (Sandbox Code Playgroud)

设置contentTitle由`的setTitle(字符串):

public NotificationHelper setTitle(String format) {
    notificationBuilder.setContentTitle(format);
    return this;
}
Run Code Online (Sandbox Code Playgroud)

smallIcon通过调用设置(状态图标)setStatusIcon(int)

public NotificationHelper setStatusIcon(int res_id) {
    notificationBuilder.setSmallIcon(res_id);
    return this;
}
Run Code Online (Sandbox Code Playgroud)

最后,通过以下方式更新通知以显示结果设置:

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);
}
Run Code Online (Sandbox Code Playgroud)

- 取消通知

正如预期的那样,取消通知就像调用一样简单cancelNotification()

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

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

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

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

我试过什么

  • 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);
}
Run Code Online (Sandbox Code Playgroud)
  • 通过调用和重新通知更新来清除setContentIntent()setContentIntent(null)

  • 我也尝试创建一个新的通知是取消setAutoCancel(true),并设置中状态setOngoing(false)和再通知到更新

这也没有帮助。有什么我可能会遗漏的吗?

我还应该提到这一点:在调试我的应用程序时,我注意到当我退出应用程序时(绑定服务停止并调用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();
    }
}
Run Code Online (Sandbox Code Playgroud)

Com*_*are 2

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