在安卓8及以上的设备必须为Notification设置channelId,通知才会显示出来但是还是有一些细节是需要注意的,下面罗列一些遇到过的问题

问题一 channelId

下面为通知设置channelId的代码如下

public static final String CHANNEL_ID_FOR_TASK = "task";
    public static final String CHANNEL_ID_FOR_DOWNLOAD = "DOWNLOAD";

    public static void initChannel(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            String channelName = context.getString(R.string.ticket_task);
            int importance = NotificationManager.IMPORTANCE_DEFAULT;
            NotificationChannel channel = createNotificationChannel(CHANNEL_ID_FOR_TASK, channelName, importance);
            NotificationChannel channel1 = createNotificationChannel(CHANNEL_ID_FOR_DOWNLOAD, "下载视频", importance);
            NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            if (notificationManager == null) {
                return;
            }
            List<NotificationChannel> channelList = new ArrayList<>();
            channelList.add(channel);
            channelList.add(channel1);
            notificationManager.createNotificationChannels(channelList);
        }
    }

    @TargetApi(Build.VERSION_CODES.O)
    private static NotificationChannel createNotificationChannel(String channelId, String channelName, int importance) {
        return new NotificationChannel(channelId, channelName, importance);
    }

以上代码设置了两个通知的频道,打开应用的通知管理可以看到通知如下,下图左侧在应用首次安装时默认开启

Android 31 通知栏不展示 安卓10通知栏_android


创建通知频道时有三个参数

channelId // 用于区别各个频道  
channelName // 通知的频道名称
importance // 该频道的重要等级
// 上图右侧通知重要程度分别对应如下代码 4 3 2 1
 /**
     * Min notification importance: only shows in the shade, below the fold.  This should
     * not be used with {@link Service#startForeground(int, Notification) Service.startForeground}
     * since a foreground service is supposed to be something the user cares about so it does
     * not make semantic sense to mark its notification as minimum importance.  If you do this
     * as of Android version {@link android.os.Build.VERSION_CODES#O}, the system will show
     * a higher-priority notification about your app running in the background.
     */
    public static final int IMPORTANCE_MIN = 1;

    /**
     * Low notification importance: shows everywhere, but is not intrusive.
     */
    public static final int IMPORTANCE_LOW = 2;

    /**
     * Default notification importance: shows everywhere, makes noise, but does not visually
     * intrude.
     */
    public static final int IMPORTANCE_DEFAULT = 3;

    /**
     * Higher notification importance: shows everywhere, makes noise and peeks. May use full screen
     * intents.
     */
    public static final int IMPORTANCE_HIGH = 4;
问题二notification.flags

必须同时设置channelflags,在安卓8及以上设备通知才会显示出来,关于flags不做过多讲解,支持的flags如下

// 代码太多去掉了注释
	@Deprecated
    public static final int FLAG_SHOW_LIGHTS        = 0x00000001;
    public static final int FLAG_ONGOING_EVENT      = 0x00000002;
    public static final int FLAG_INSISTENT          = 0x00000004;
    public static final int FLAG_ONLY_ALERT_ONCE    = 0x00000008;
    public static final int FLAG_AUTO_CANCEL        = 0x00000010;
    public static final int FLAG_NO_CLEAR           = 0x00000020;
    public static final int FLAG_FOREGROUND_SERVICE = 0x00000040;
    @Deprecated
    public static final int FLAG_HIGH_PRIORITY      = 0x00000080;
    public static final int FLAG_LOCAL_ONLY         = 0x00000100;
    public static final int FLAG_GROUP_SUMMARY      = 0x00000200;

下面对FLAG_ONGOING_EVENT做一些讲解,当你使用通知栏通知进度时(比如下载文件)会用到这个FLAG_ONGOING_EVENT,这个有遇到过一个坑,当你的界面是继承android.app.Activityandroid.app.Fragment时,使用FLAG_ONGOING_EVENT,通知不会弹出来,即使你在界面启动Service然后在Service里发通知通知也不会弹出来,换成继承android.support.v7.app.AppCompatActivityandroid.support.v4.app.Fragment就不会有问题,下面上一个通知栏通知进度的demo

private void start() {
        Log.d(TAG, "start");
        mBuilder = new NotificationCompat.Builder(this, NotificationChannelHelper.CHANNEL_ID_FOR_DOWNLOAD);
        mBuilder.setDefaults(Notification.DEFAULT_ALL) // 设置通知的震动、声音等
                .setOngoing(true) // true 不可取消,即通知不能清除 false 可通过左右滑或清除按钮清除通知
                .setPriority(Notification.PRIORITY_MIN) // 重要等级
//                .setLargeIcon(BitmapFactory.decodeResource(getActivity().getResources(), R.mipmap.ic_launcher))
//                .setContentIntent(pendingIntent)
                .setStyle(new NotificationCompat.BigTextStyle().bigText("地方东方闪电范甘迪发个梵蒂冈地方高度分工的风格大方梵蒂冈电饭锅多个地方d大幅度多个发光飞碟电饭锅地方负担d大幅度多个发光飞碟电饭锅地方负担d大幅度多个发光飞碟电饭锅地方负担d大幅度多个发光飞碟电饭锅地方负担d大幅度多个发光飞碟电饭锅地方负担d大幅度多个发光飞碟电饭锅地方负担")) // 可设置文本内容多行显示,如果不做此设置,则下图显示的是 setContentText 的内容
                .setSmallIcon(R.mipmap.ic_launcher) // 安卓8及以上必须设置,否则部分手机会直接崩溃 
                .setContentTitle("测试")
                .setContentText("测试通知")
                .setTicker("正在进行");
        update();
    }

    private int count;

    private void update() {
        Log.d("FavouriteFragment", "update count:" + count);
        if (count < 30) {
            if (count != 0) {
                mBuilder.setProgress(30, count, false);
            }
            Notification notification = mBuilder.build();
            notification.flags = Notification.FLAG_ONGOING_EVENT;
            getManager().notify(121, notification);
            mHandler.postDelayed(this::update, 800);
            count++;
        } else {
            count = 0;
            getManager().cancel(121);
        }
    }

    protected NotificationManager getManager() {
        if (manager == null) {
            manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        }
        return manager;
    }

Android 31 通知栏不展示 安卓10通知栏_Android 31 通知栏不展示_02

安卓6及以上必须设置 setSmallIcon ,下面是调用notify后的代码,没有设置会抛异常导致应用崩溃
public void notifyAsUser(String tag, int id, Notification notification, UserHandle user)
    {
        INotificationManager service = getService();
        String pkg = mContext.getPackageName();
        // Fix the notification as best we can.
        Notification.addFieldsFromContext(mContext, notification);

        if (notification.sound != null) {
            notification.sound = notification.sound.getCanonicalUri();
            if (StrictMode.vmFileUriExposureEnabled()) {
                notification.sound.checkFileUriExposed("Notification.sound");
            }

        }
        fixLegacySmallIcon(notification, pkg);
        if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
            if (notification.getSmallIcon() == null) {
                throw new IllegalArgumentException("Invalid notification (no valid small icon): "
                        + notification);
            }
        }
        if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
        notification.reduceImageSizes(mContext);

        ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
        boolean isLowRam = am.isLowRamDevice();
        final Notification copy = Builder.maybeCloneStrippedForDelivery(notification, isLowRam,
                mContext);
        try {
            service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
                    copy, user.getIdentifier());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }