Notification 总结

Notification

Notification 能干什么,那些设计是和Notification相关的;这里直接从官网取图,直接看图;

notification statues bar 提示

swipe down show notifacation detail

heads-up notification

Lock screen
App icon badge
INBOX_STYLE
BIG_PICTURE_STYLE
MESSAGING_STYLE
A notification with basic details 一般Notification的样式
通过setStyle方法修改了style的样式可能就是这样子的.png

可以直接回复消息,快捷回复等;

针对一般Notification的样式
The most common parts of a notification are indicated in figure 7 as follows:

  1. Small icon: This is required and set with setSmallIcon().
  2. App name: This is provided by the system.
  3. Time stamp: This is provided by the system but you can override with setWhen() or hide it with setShowWhen(false).
  4. Large icon: This is optional (usually used only for contact photos; do not use it for your app icon) and set withsetLargeIcon().
  5. Title: This is optional and set with setContentTitle().
  6. Text: This is optional and set with setContentText().

setStyle() 抽象类Style 有种实现类,分别是:
1:BigTextStyle 处理大量文案样式;
2: MediaStyle 处理多媒体通知样式;
3: DecoratedCustomViewStyle 自定义包装样式;
4: NessagingStyle 消息样式;
5: BigPictureStyle 展示大图样式;
6: InboxStyle 展示消息在同一个box的样式;

Style 继承结构

大概步骤:
// Main steps for building a BIG_TEXT_STYLE notification:
// 0. Get your data
// 1. Create/Retrieve Notification Channel for O and beyond devices (26+)
// 2. Build the BIG_TEXT_STYLE
// 3. Set up main Intent for notification
// 4. Create additional Actions for the Notification
// 5. Build and issue the notification

 // 根据id,取消对应的notifcation
 NotificationManagerCompat notificationManagerCompat =
                NotificationManagerCompat.from(getApplicationContext());
        notificationManagerCompat.cancel(MainActivity.NOTIFICATION_ID);

简单使用

  1. Create/Retrieve Notification Channel for O and beyond devices (26+)(必须)
  2. Build the BIG_TEXT_STYLE(可选)
  3. Set up main Intent for notification(可选)
  4. Create additional Actions for the Notification(可选)
  5. Build and issue the notification(必须)

下面是具体代码 来着Google 官方demo

/*
     * Generates a BIG_TEXT_STYLE Notification that supports both phone/tablet and wear. For devices
     * on API level 16 (4.1.x - Jelly Bean) and after, displays BIG_TEXT_STYLE. Otherwise, displays
     * a basic notification.
     */
    private void generateBigTextStyleNotification() {
 
        // Main steps for building a BIG_TEXT_STYLE notification:
        //      0. Get your data
        //      1. Create/Retrieve Notification Channel for O and beyond devices (26+)
        //      2. Build the BIG_TEXT_STYLE
        //      3. Set up main Intent for notification
        //      4. Create additional Actions for the Notification
        //      5. Build and issue the notification

        // 0. Get your data (everything unique per Notification). 
        //通过一个类将数据都封装在这个类中,统一管理
        MockDatabase.BigTextStyleReminderAppData bigTextStyleReminderAppData =
                MockDatabase.getBigTextStyleData();

        // 1. Create/Retrieve Notification Channel for O and beyond devices (26+).
        //  在Android O 之后非常必要的操作,这里有个小细节关于在Kotlin中创建channel,
        String notificationChannelId =
                NotificationUtil.createNotificationChannel(this, bigTextStyleReminderAppData);


        // 2. Build the BIG_TEXT_STYLE.
        //  使用style 样式 
        BigTextStyle bigTextStyle = new NotificationCompat.BigTextStyle()
                // Overrides ContentText in the big form of the template.
                // 如果点击展开消息内容的箭头:bigText的内容会覆盖在notification中设置的设置的内容(ContentText);
                .bigText(bigTextStyleReminderAppData.getBigText())
                // Overrides ContentTitle in the big form of the template.
                // 如果点击展开消息内容的箭头:bigContentTitle的内容会覆盖notification中设置的内容(ContentTitle)
                .setBigContentTitle(bigTextStyleReminderAppData.getBigContentTitle())
                // Summary line after the detail section in the big form of the template.
                // Note: To improve readability, don't overload the user with info. If Summary Text
                // doesn't add critical information, you should skip it.
                // 设置总结消息提示 :<SummaryText 总结> 内容不能过长,太长也会省略为 xxx.xxxxx... 的形式
                .setSummaryText(bigTextStyleReminderAppData.getSummaryText());


        // 3. Set up main Intent for notification 
        // (给PendingIntent 绑定的真正 Intent )这里可以使Activity 或者 Service,
        //  但是绑定PendingIntent 时需要注意API 的调用(具体事例中有)
        //  务必记得 单打开对应的Activity 或者 Service ,有必要执行cancel 掉对应的notification
       
        Intent notifyIntent = new Intent(this, BigTextMainActivity.class);

        // When creating your Intent, you need to take into account the back state, i.e., what
        // happens after your Activity launches and the user presses the back button.

        // There are two options:
        //      1. Regular activity - You're starting an Activity that's part of the application's
        //      normal workflow.

        //      2. Special activity - The user only sees this Activity if it's started from a
        //      notification. In a sense, the Activity extends the notification by providing
        //      information that would be hard to display in the notification itself.

        // For the BIG_TEXT_STYLE notification, we will consider the activity launched by the main
        // Intent as a special activity, so we will follow option 2.

        // For an example of option 1, check either the MESSAGING_STYLE or BIG_PICTURE_STYLE
        // examples.

        // For more information, check out our dev article:
        // https://developer.android.com/training/notify-user/navigation.html

        // Sets the Activity to start in a new, empty task
        notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

        PendingIntent notifyPendingIntent =
                PendingIntent.getActivity(
                        this,
                        0,
                        notifyIntent,
                        PendingIntent.FLAG_UPDATE_CURRENT
                );


        // 4. Create additional Actions (Intents) for the Notification.
        // 创建 Actions (Intents)  效果直接看图

        // In our case, we create two additional actions: a Snooze action and a Dismiss action.
        // Snooze Action.
        Intent snoozeIntent = new Intent(this, BigTextIntentService.class);
        snoozeIntent.setAction(BigTextIntentService.ACTION_SNOOZE);

        PendingIntent snoozePendingIntent = PendingIntent.getService(this, 0, snoozeIntent, 0);
        NotificationCompat.Action snoozeAction =
                new NotificationCompat.Action.Builder(
                        R.drawable.ic_alarm_white_48dp,
                        "Snooze",
                        snoozePendingIntent)
                        .build();


        // Dismiss Action.
        Intent dismissIntent = new Intent(this, BigTextIntentService.class);
        dismissIntent.setAction(BigTextIntentService.ACTION_DISMISS);

        PendingIntent dismissPendingIntent = PendingIntent.getService(this, 0, dismissIntent, 0);
        NotificationCompat.Action dismissAction =
                new NotificationCompat.Action.Builder(
                        R.drawable.ic_cancel_white_48dp,
                        "Dismiss",
                        dismissPendingIntent)
                        .build();


        // 5. Build and issue the notification.

        // Because we want this to be a new notification (not updating a previous notification), we
        // create a new Builder. Later, we use the same global builder to get back the notification
        // we built here for the snooze action, that is, canceling the notification and relaunching
        // it several seconds later.

        // Notification Channel Id is ignored for Android pre O (26).
        NotificationCompat.Builder notificationCompatBuilder =
                new NotificationCompat.Builder(
                        getApplicationContext(), notificationChannelId);

        GlobalNotificationBuilder.setNotificationCompatBuilderInstance(notificationCompatBuilder);

        Notification notification = notificationCompatBuilder
                // BIG_TEXT_STYLE sets title and content for API 16 (4.1 and after).
                .setStyle(bigTextStyle) // 设置样式
                // Title for API <16 (4.0 and below) devices.
                .setContentTitle(bigTextStyleReminderAppData.getContentTitle())  //设置未展开时的标题
                // Content for API <24 (7.0 and below) devices.
                .setContentText(bigTextStyleReminderAppData.getContentText()) // 设置未展开时的内容
                .setSmallIcon(R.drawable.ic_launcher) // 设置顶部smallIcon
                .setLargeIcon(BitmapFactory.decodeResource( // 设置右侧LargeIcon 注意颜色,白色可就看不到了
                        getResources(),
                        R.drawable.ic_action_name1))
                .setContentIntent(notifyPendingIntent)
                .setDefaults(NotificationCompat.DEFAULT_ALL) // 设置声音 ,震动,默认等
                // Set primary color (important for Wear 2.0 Notifications). 这个颜色会同步到smallIcon , action 字体颜色
                .setColor(ContextCompat.getColor(getApplicationContext(), R.color.colorAccent))

                // SIDE NOTE: Auto-bundling is enabled for 4 or more notifications on API 24+ (N+)
                // devices and all Wear devices. If you have more than one notification and
                // you prefer a different summary notification, set a group key and create a
                // summary notification via
//                 .setGroupSummary(true)
//                 .setGroup(GROUP_KEY_YOUR_NAME_HERE)

                .setCategory(Notification.CATEGORY_MESSAGE) // 设置消息类型

                // Sets priority for 25 and below. For 26 and above, 'priority' is deprecated for
                // 'importance' which is set in the NotificationChannel. The integers representing
                // 'priority' are different from 'importance', so make sure you don't mix them.
                .setPriority(bigTextStyleReminderAppData.getPriority())

                // Sets lock-screen visibility for 25 and below. For 26 and above, lock screen
                // visibility is set in the NotificationChannel.
                .setVisibility(bigTextStyleReminderAppData.getChannelLockscreenVisibility())
.setBadgeIconType(NotificationCompat.BADGE_ICON_SMALL) // 是否展示在桌面icon 上展示徽章 badge
                // Adds additional actions specified above.
                .addAction(snoozeAction)
                .addAction(dismissAction)

                .build();

        mNotificationManagerCompat.notify(NOTIFICATION_ID, notification);
    }
样例图

1:应用名 和 时间之间的内容是总结内容,SummaryText;
2: setColor 会影响图标颜色,和 Actions 文字颜色,但是不会影响状态栏的图标;
3: 当有消息时,8.0系统 桌面icon 边上的可以控制展示不展示

val id = "my_channel_01"
val name = getString(R.string.channel_name)
val descriptionText = getString(R.string.channel_description)
val importance = NotificationManager.IMPORTANCE_LOW
val mChannel = NotificationChannel(id, name, importance).apply {
    description = descriptionText
    setShowBadge(false) //关键代码
}
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(mChannel)

Note :

1:Kotlin 的 创建NotificationCompat.Builder时;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            channelID = "channelID"
            var channel = NotificationChannel(channelID, "this is name ", NotificationManager.IMPORTANCE_DEFAULT)
            val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannel(channel)
        }

        if (channelID == null) {
            //注意这里,如果channelID 为可空类型时,
            //不能使用NotificationCompat.Builder(this, channelID) 所以如此处理
            builder = NotificationCompat.Builder(this)
        } else {
            builder = NotificationCompat.Builder(this, channelID!!) 
        }

2: Android 8.0 之后需要创建Channel,创建Notification需要ChannelID;

// 代码来着Google dome
 public static String createNotificationChannel(
            Context context,
            MockDatabase.MockNotificationData mockNotificationData) {

        // NotificationChannels are required for Notifications on O (API 26) and above.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

            // The id of the channel.
            String channelId = mockNotificationData.getChannelId();

            // The user-visible name of the channel.
            CharSequence channelName = mockNotificationData.getChannelName();
            // The user-visible description of the channel.
            String channelDescription = mockNotificationData.getChannelDescription();
            //NotificationManager.IMPORTANCE_MAX;IMPORTANCE_HIGH;IMPORTANCE_DEFAULT;      
//IMPORTANCE_LOW;IMPORTANCE_MIN;IMPORTANCE_NONE;IMPORTANCE_UNSPECIFIED;
            int channelImportance = mockNotificationData.getChannelImportance();
            boolean channelEnableVibrate = mockNotificationData.isChannelEnableVibrate();
            int channelLockscreenVisibility =
                    mockNotificationData.getChannelLockscreenVisibility();

            // Initializes NotificationChannel.  构造(ID, 名字,重要程度)
            NotificationChannel notificationChannel =
                    new NotificationChannel(channelId, channelName, channelImportance);
            notificationChannel.setDescription(channelDescription);
            notificationChannel.enableVibration(channelEnableVibrate);
           // NotificationCompat.VISIBILITY_PRIVATE;VISIBILITY_PRIVATE;VISIBILITY_PUBLIC
            notificationChannel.setLockscreenVisibility(channelLockscreenVisibility);

            // Adds NotificationChannel to system. Attempting to create an existing notification
            // channel with its original values performs no operation, so it's safe to perform the
            // below sequence.
            NotificationManager notificationManager =
                    (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            notificationManager.createNotificationChannel(notificationChannel);

            return channelId;
        } else {
            // Returns null for pre-O (26) devices.
            return null;
        }
    }

3: PendingIntent中的绑定的intent 可以Activity是Service(比如 IntentService 的子类);

从上面贴的示例代码也可以看出;
PendingIntent snoozePendingIntent = PendingIntent.getService(this, 0, snoozeIntent, 0);

PendingIntent notifyPendingIntent =
                PendingIntent.getActivity(
                        this,
                        0,
                        notifyIntent,
                        PendingIntent.FLAG_UPDATE_CURRENT
                );   

但是:按照我的理解,一般setContentIntent 绑定的是Acitivity ,addAction 绑定的是Service

4:取消notification记得使用;不管是在activity 还是service

NotificationManagerCompat notificationManagerCompat =
                NotificationManagerCompat.from(getApplicationContext());
         // 根据Notification_ID 取消指定的Notification
        notificationManagerCompat.cancel(MainActivity.NOTIFICATION_ID);

官方删除Notification如下:

  • The user dismisses the notification.
  • The user clicks the notification, and you called setAutoCancel() when you created the notification.
  • You call cancel() for a specific notification ID. This method also deletes ongoing notifications.
  • You call cancelAll(), which removes all of the notifications you previously issued.
  • If you set a timeout when creating a notification using setTimeoutAfter(), the system cancels the notification after the specified duration elapses. If required, you can cancel a notification before the specified timeout duration elapses.

Heads-up 效果

抬头通知会在您的应用发出通知时出现,并在片刻后消失,但仍会像往常一样在通知抽屉中显示。

可能触发抬头通知的示例条件包括:

  • 用户的活动处于全屏模式(应用程序使用 fullScreenIntent)。
  • 该通知具有高优先级,并在运行Android 7.1(API级别25)及更低级别的设备上使用铃声或振动。setDefaults(NotificationCompat.DEFAULT_ALL)
  • 通知渠道对运行Android 8.0(API级别26)及更高版本的设备具有高度重要性。setPriority 以及 NotificationChannel(channelId, channelName, channelImportance)

Actions 的相应

  // 4. Create additional Actions (Intents) for the Notification.

       // In our case, we create two additional actions: a Snooze action and a Dismiss action.
       // Snooze Action.
       Intent snoozeIntent = new Intent(this, BigTextIntentService.class);
       snoozeIntent.setAction(BigTextIntentService.ACTION_SNOOZE);

       PendingIntent snoozePendingIntent = PendingIntent.getService(this, 0, snoozeIntent, 0);
       NotificationCompat.Action snoozeAction =
               new NotificationCompat.Action.Builder(
                       R.drawable.ic_alarm_white_48dp,
                       "Snooze",
                       snoozePendingIntent)
                       .build();

BigTextIntentService

public class BigTextIntentService extends IntentService {

    private static final String TAG = "BigTextService";

    public static final String ACTION_DISMISS =
            "com.example.android.wearable.wear.wearnotifications.handlers.action.DISMISS";
    public static final String ACTION_SNOOZE =
            "com.example.android.wearable.wear.wearnotifications.handlers.action.SNOOZE";

    private static final long SNOOZE_TIME = TimeUnit.SECONDS.toMillis(5);

    public BigTextIntentService() {
        super("BigTextIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Log.d(TAG, "onHandleIntent(): " + intent);

        if (intent != null) {
            final String action = intent.getAction();
            if (ACTION_DISMISS.equals(action)) {
                handleActionDismiss(); //cancleNotification
            } else if (ACTION_SNOOZE.equals(action)) {
                handleActionSnooze(); //发送Notification
            }
        }
    }
}

RemoteInuput 类似Reply的

 // Create the RemoteInput.
        String replyLabel = getString(R.string.reply_label);
        RemoteInput remoteInput =
                new RemoteInput.Builder(BigPictureSocialIntentService.EXTRA_COMMENT)
                        .setLabel(replyLabel)
                        // List of quick response choices for any wearables paired with the phone
                        .setChoices(bigPictureStyleSocialAppData.getPossiblePostResponses())
                        .build();

        // Pending intent =
        //      API <24 (M and below): activity so the lock-screen presents the auth challenge
        //      API 24+ (N and above): this should be a Service or BroadcastReceiver
        PendingIntent replyActionPendingIntent;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            Intent intent = new Intent(this, BigPictureSocialIntentService.class);
            intent.setAction(BigPictureSocialIntentService.ACTION_COMMENT);
            replyActionPendingIntent = PendingIntent.getService(this, 0, intent, 0);

        } else {
            replyActionPendingIntent = mainPendingIntent;
        }

        NotificationCompat.Action replyAction =
                new NotificationCompat.Action.Builder(
                        R.drawable.ic_reply_white_18dp,
                        replyLabel,
                        replyActionPendingIntent)
                        .addRemoteInput(remoteInput)
                        .build();

// 最后addAction(replyAction) 到Notificationbuilder
BigPictureSocialIntentService 中获取输入的关键代码
    /*
     * Extracts CharSequence created from the RemoteInput associated with the Notification.
     */
    private CharSequence getMessage(Intent intent) {
        Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
        if (remoteInput != null) {
            return remoteInput.getCharSequence(EXTRA_COMMENT);
        }
        return null;
    }

补充 Notes:

1:如果多个通道使用Heads-up效果 会导致失效;
2: Beginning with Android 8.1 (API level 27), apps cannot make a notification sound more than once per second. If your app posts multiple notifications in one second, they all appear as expected, but only the first notification per second makes a sound.
8.1 以后每秒只能发生一个Notification;

更多细节参考官网和官方Demo

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,658评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,482评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,213评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,395评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,487评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,523评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,525评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,300评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,753评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,048评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,223评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,905评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,541评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,168评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,417评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,094评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,088评论 2 352

推荐阅读更多精彩内容