Android Notification 使用

如何創(chuàng)建通知

隨著Android系統(tǒng)不斷升級耳幢,Notification的創(chuàng)建方式也隨之變化岳守,主要變化如下:

Android 3.0之前

Android 3.0 (API level 11)之前铲掐,使用new Notification()方式創(chuàng)建通知:

NotificationManager mNotifyMgr = 
      (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(
      this, 0, new Intent(this, ResultActivity.class), 0);

Notification notification = new Notification(icon, tickerText, when);
notification.setLatestEventInfo(this, title, content, contentIntent);

mNotifyMgr.notify(NOTIFICATIONS_ID, notification);

Android 3.0 (API level 11)及更高版本

Android 3.0開始棄用new Notification()方式位隶,改用Notification.Builder()來創(chuàng)建通知:

NotificationManager mNotifyMgr = 
      (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(
      this, 0, new Intent(this, ResultActivity.class), 0);

Notification notification = new Notification.Builder(this)
            .setSmallIcon(R.drawable.notification_icon)
            .setContentTitle("My notification")
            .setContentText("Hello World!")
            .setContentIntent(contentIntent)
            .build();// getNotification()

mNotifyMgr.notify(NOTIFICATIONS_ID, notification);

這里需要注意:
"build()" 是Androdi 4.1(API level 16)加入的怨规,用以替代
"getNotification()"絮吵。API level 16開始棄用"getNotification()"

兼容Android 3.0之前的版本

為了兼容API level 11之前的版本弧烤,v4 Support Library中提供了
NotificationCompat.Builder()這個(gè)替代方法。它與Notification.Builder()類似蹬敲,二者沒有太大區(qū)別暇昂。

NotificationManager mNotifyMgr = 
      (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(
      this, 0, new Intent(this, ResultActivity.class), 0);

NotificationCompat.Builder mBuilder = 
      new NotificationCompat.Builder(this)
            .setSmallIcon(R.drawable.notification_icon)
            .setContentTitle("My notification")
            .setContentText("Hello World!")
            .setContentIntent(contentIntent);

mNotifyMgr.notify(NOTIFICATIONS_ID, mBuilder.build());

范例:

     /**
     * 普通樣式
     *
     * @param context
     */
    private void simpleNotify(Context context) {
        initNotificationManager(context);
        //為了版本兼容  選擇V7包下的NotificationCompat進(jìn)行構(gòu)造
        NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
        //Ticker是狀態(tài)欄顯示的提示
        builder.setTicker("簡單Notification");
        //第一行內(nèi)容  通常作為通知欄標(biāo)題
        builder.setContentTitle("標(biāo)題");
        //第二行內(nèi)容 通常是通知正文
        builder.setContentText("通知內(nèi)容");
        //第三行內(nèi)容 通常是內(nèi)容摘要什么的 在低版本機(jī)器上不一定顯示
        builder.setSubText("這里顯示的是通知第三行內(nèi)容!");
        //ContentInfo 在通知的右側(cè) 時(shí)間的下面 用來展示一些其他信息
        //builder.setContentInfo("3");
        //number設(shè)計(jì)用來顯示同種通知的數(shù)量和ContentInfo的位置一樣伴嗡,如果設(shè)置了ContentInfo則number會(huì)被隱藏
        builder.setNumber(2);
        //可以點(diǎn)擊通知欄的刪除按鈕刪除
        builder.setAutoCancel(true);
        //系統(tǒng)狀態(tài)欄顯示的小圖標(biāo)
        builder.setSmallIcon(R.drawable.notify_5);
        //下拉顯示的大圖標(biāo)
        builder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.launcher_sohu));
        Intent intent = new Intent(context, PendingActivity.class);
        PendingIntent pIntent = PendingIntent.getActivity(context, 1, intent, 0);
        //點(diǎn)擊跳轉(zhuǎn)的intent
        builder.setContentIntent(pIntent);
        //通知默認(rèn)的聲音 震動(dòng) 呼吸燈
        builder.setDefaults(NotificationCompat.DEFAULT_ALL);
        Notification notification = builder.build();
        notificationManager.notify(TYPE_Normal, notification);
    }
普通樣式.png
    /**
     * 多文本樣式
     * @param context
     */
    private void bigTextStyle(Context context) {
        initNotificationManager(context);
        //為了版本兼容  選擇V7包下的NotificationCompat進(jìn)行構(gòu)造
        NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
        builder.setContentTitle("BigTextStyle");
        builder.setContentText("BigTextStyle演示示例");
        builder.setSmallIcon(R.drawable.notify_5);
        builder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.launcher_sohu));
        android.support.v4.app.NotificationCompat.BigTextStyle style = new android.support.v4.app.NotificationCompat.BigTextStyle();
        style.bigText("這里是點(diǎn)擊通知后要顯示的正文急波,可以換行可以顯示很長很長很長很長很長很長很長很長很長很長很長很長很長很長很長很長很長很長");
        style.setBigContentTitle("點(diǎn)擊后的標(biāo)題");
        style.setSummaryText("末尾只一行的文字內(nèi)容");
        builder.setStyle(style);
        builder.setAutoCancel(true);
        Intent intent = new Intent(context, PendingActivity.class);
        PendingIntent pIntent = PendingIntent.getActivity(context, 1, intent, 0);
        builder.setContentIntent(pIntent);
        builder.setDefaults(NotificationCompat.DEFAULT_ALL);
        Notification notification = builder.build();
        notificationManager.notify(TYPE_BigText, notification);
    }
多文本樣式.png
/**
     * 最多顯示五行 再多會(huì)有截?cái)?     */
    public void inBoxStyle(Context context) {
        initNotificationManager(context);
        //為了版本兼容  選擇V7包下的NotificationCompat進(jìn)行構(gòu)造
        NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
        builder.setContentTitle("InboxStyle");
        builder.setContentText("InboxStyle演示示例");
        builder.setSmallIcon(R.drawable.notify_5);
        builder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.launcher_sohu));
        android.support.v4.app.NotificationCompat.InboxStyle style = new android.support.v4.app.NotificationCompat.InboxStyle();
        style.setBigContentTitle("BigContentTitle")
                .addLine("第一行,第一行瘪校,第一行澄暮,第一行,第一行阱扬,第一行泣懊,第一行")
                .addLine("第二行")
                .addLine("第三行")
                .addLine("第四行")
                .addLine("第五行")
                .setSummaryText("SummaryText");
        builder.setStyle(style);
        builder.setAutoCancel(true);
        Intent intent = new Intent(context, PendingActivity.class);
        PendingIntent pIntent = PendingIntent.getActivity(context, 1, intent, 0);
        builder.setContentIntent(pIntent);
        builder.setDefaults(NotificationCompat.DEFAULT_ALL);
        Notification notification = builder.build();
        notificationManager.notify(TYPE_Inbox, notification);
    }
inBoxStyle.png
    /**
     * 大圖樣式
     * @param context
     */
    public void bigPictureStyle(Context context) {
        initNotificationManager(context);
        //為了版本兼容  選擇V7包下的NotificationCompat進(jìn)行構(gòu)造
        NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
        builder.setContentTitle("BigPictureStyle");
        builder.setContentText("BigPicture演示示例");
        builder.setSmallIcon(R.drawable.notify_5);
        builder.setDefaults(NotificationCompat.DEFAULT_ALL);
        builder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.launcher_sohu));
        android.support.v4.app.NotificationCompat.BigPictureStyle style = new android.support.v4.app.NotificationCompat.BigPictureStyle();
        style.setBigContentTitle("BigContentTitle");
        style.setSummaryText("SummaryText");
        style.bigPicture(BitmapFactory.decodeResource(context.getResources(), R.drawable.small));
        builder.setStyle(style);
        builder.setAutoCancel(true);
        Intent intent = new Intent(context, PendingActivity.class);
        PendingIntent pIntent = PendingIntent.getActivity(context, 1, intent, 0);
        builder.setContentIntent(pIntent);
        Notification notification = builder.build();
        notificationManager.notify(TYPE_BigPicture, notification);
    }

大圖樣式.png
    /**
     * 橫幅通知
     *
     * @param context
     */
    private void hangup(Context context) {
        initNotificationManager(context);
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            Toast.makeText(context, "此類通知在Android 5.0以上版本才會(huì)有橫幅有效!", Toast.LENGTH_SHORT).show();
        }
        //為了版本兼容  選擇V7包下的NotificationCompat進(jìn)行構(gòu)造
        NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
        builder.setContentTitle("橫幅通知");
        builder.setContentText("請?jiān)谠O(shè)置通知管理中開啟消息橫幅提醒權(quán)限");
        builder.setDefaults(NotificationCompat.DEFAULT_ALL);
        builder.setSmallIcon(R.drawable.notify_5);
        builder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.launcher_sohu));
        Intent intent = new Intent(context, PendingActivity.class);
        PendingIntent pIntent = PendingIntent.getActivity(context, 1, intent, 0);
        builder.setContentIntent(pIntent);
        builder.setFullScreenIntent(pIntent, true);
        builder.setAutoCancel(true);
        Notification notification = builder.build();
        notificationManager.notify(TYPE_Hangup, notification);
    }
橫幅通知.png

自定義通知適配

默認(rèn)通知不存在樣式適配的問題麻惶,因?yàn)槟J(rèn)通知的布局馍刮、顏色、背景什么的都是系統(tǒng)的窃蹋,系統(tǒng)總會(huì)正確的顯示默認(rèn)通知渠退。但自定義通知就不一樣了,自定義通知的布局完全由我們自己掌控脐彩,我們可以為元素設(shè)置任何背景碎乃、顏色。那么惠奸,問題來了梅誓。Android通知欄的背景各種各樣,不同的ROM有不同的背景佛南,白色梗掰、黑色、透明等嗅回。不同的Android版本通知欄背景也不一樣及穗,一旦我們?yōu)樽远x通知上的元素設(shè)置了特定背景或顏色,就肯定會(huì)帶來兼容性問題

2234662-79c45320c4fa7079.png

適配的方式大概有兩種:
一種簡單粗暴:為自定義通知設(shè)置固定的背景(上圖中的360衛(wèi)士就這么干的)绵载,比如黑色埂陆。那么內(nèi)容自然就是白色或近似白色苛白。這樣,在所有的手機(jī)上都能正常顯示焚虱,不會(huì)出現(xiàn)在黑色背景通知欄上顯示良好购裙,到了白色背景通知欄上就幾乎啥也看不見。
另一種方案就稍微合理一些:通過讀取系統(tǒng)的通知欄樣式文件鹃栽,獲取到title和content的顏色躏率,進(jìn)而將這個(gè)顏色設(shè)置到自定義通知上。讀取通知欄樣式文件本身有兼容性問題民鼓,不同Android版本的樣式文件有變薇芝,種方式也不是在所有手機(jī)上生效,實(shí)際測試發(fā)現(xiàn)丰嘉,還是有小部分機(jī)型沒法讀取或是讀取到的是錯(cuò)誤的夯到。拿到title和content的顏色后,還可以通過算法(后面細(xì)說)判斷這個(gè)顏色是近似白色還是近似黑色供嚎,進(jìn)而能判斷出通知欄的背景是近似黑色還是近似白色黄娘,這樣就能根據(jù)不同的通知欄背景加載不同的自定義通知布局峭状。進(jìn)而做到良好的適配克滴。

/**
 * 讀取系統(tǒng)通知欄顏色工具類
 * Created by liuboyu on 16/12/21.
 */
public class SystemColorUtils {

    private static final String DUMMY_TITLE = "DUMMY_TITLE";
    private static final double COLOR_THRESHOLD = 180.0;
    private static int titleColor;

    /**
     * 獲取通知欄顏色
     *
     * @param context
     * @return
     */
    public static int getNotificationColor(Context context) {
//        if (context instanceof AppCompatActivity) {
//            return getNotificationColorCompat(context);
//        } else {
        return getNotificationColorInternal(context);
//        }
    }

    /**
     * 當(dāng)前狀態(tài)了是否為暗色
     *
     * @param context
     * @return
     */
    public static boolean isDarkNotificationBar(Context context) {
        return !isColorSimilar(Color.BLACK, getNotificationColor(context));
    }


    /**
     * notificationRoot了,不如就遍歷它优床,先找到其中的所有TextView
     * 取字體最大的TextView作為title(這是合理的劝赔,
     * 因?yàn)槟J(rèn)通知中最多也就4個(gè)TextView,分別是title胆敞、
     * content着帽、info、when移层,title肯定是字體最大仍翰,最顯眼的)
     *
     * @param context
     * @return
     */
    public static int getNotificationColorCompat(Context context) {
        NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
        Notification notification = builder.build();
        int layoutId = notification.contentView.getLayoutId();
        ViewGroup notificationRoot = (ViewGroup) LayoutInflater.from(context).inflate(layoutId, null);
        final TextView title = (TextView) notificationRoot.findViewById(android.R.id.title);
        //ROM廠商會(huì)把id改掉,導(dǎo)致找到的title為空观话。
        if (null == title) {
            final List<TextView> textViews = new ArrayList<>();
            iteratorView(notificationRoot, new Filter() {
                @Override
                public void filter(View view) {
                    if (view instanceof TextView) {
                        textViews.add((TextView) view);
                    }
                }
            });

            float minTextSize = Integer.MIN_VALUE;
            int index = 0;
            for (int i = 0; i < textViews.size(); i++) {
                float currentSize = textViews.get(i).getTextSize();
                if (currentSize > minTextSize) {
                    minTextSize = currentSize;
                    index = i;
                }
            }
            return textViews.get(index).getCurrentTextColor();
        } else {
            return title.getCurrentTextColor();
        }
    }

    /**
     * 5.0以下的機(jī)器
     *
     * @param context
     * @return
     */
    public static int getNotificationColorInternal(Context context) {
        NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
        Notification notification = builder.build();
        int layoutId = notification.contentView.getLayoutId();
        ViewGroup notificationRoot = (ViewGroup) LayoutInflater.from(context).inflate(layoutId, null);
        final TextView title = (TextView) notificationRoot.findViewById(android.R.id.title);
        if (null == title) {
            iteratorView(notificationRoot, new Filter() {

                @Override
                public void filter(View view) {
                    if (view instanceof TextView) {
                        TextView textView = (TextView) view;
                        if (DUMMY_TITLE.equals(textView.getText().toString())) {
                            titleColor = textView.getCurrentTextColor();
                        }
                    }
                }
            });
            return titleColor;
        } else {
            Log.e("ddddd3ddd",""+title.getCurrentTextColor());
            return title.getCurrentTextColor();
        }
    }

    /**
     * 遍歷 notificationRoot了
     *
     * @param view
     * @param filter
     */
    private static void iteratorView(View view, Filter filter) {
        if (view == null || filter == null) {
            return;
        }
        filter.filter(view);
        if (view instanceof ViewGroup) {
            ViewGroup container = (ViewGroup) view;
            for (int i = 0, j = container.getChildCount(); i < j; i++) {
                View childAt = container.getChildAt(i);
                iteratorView(childAt, filter);
            }
        }
    }

    private interface Filter {
        void filter(View view);
    }

    /**
     * 使用方差來計(jì)算這個(gè)顏色是否近似黑色
     *
     * @param baseColor
     * @param color
     * @return
     */
    public static boolean isColorSimilar(int baseColor, int color) {
        int simpleBaseColor = baseColor | 0xff000000;
        int simpleColor = color | 0xff000000;
        int baseRed = Color.red(simpleBaseColor) - Color.red(simpleColor);
        int baseGreen = Color.green(simpleBaseColor) - Color.green(simpleColor);
        int baseBlue = Color.blue(simpleBaseColor) - Color.blue(simpleColor);
        double value = Math.sqrt(baseRed * baseRed + baseGreen * baseGreen + baseBlue * baseBlue);
        if (value < COLOR_THRESHOLD) {
            return true;
        }
        return false;
    }

}
使用范例:
       if (SystemColorUtils.isDarkNotificationBar(context)) {
            view.setTextColor(R.id.tv_title, context.getResources().getColor(R.color.white));
            view.setTextColor(R.id.tv_des, context.getResources().getColor(R.color.white));
        } else {
            view.setTextColor(R.id.tv_title, context.getResources().getColor(R.color.black));
            view.setTextColor(R.id.tv_des, context.getResources().getColor(R.color.black));
        }

需要注意的是:
如果當(dāng)前工程已經(jīng)繼承 com.android.support:appcompat 可正常使用
如果當(dāng)前工程沒有繼承 com.android.support:appcompat 予借,AppBaseTheme 要繼承 @android:style/Theme.DeviceDefault.Light.DarkActionBar,本人暫時(shí)也沒有搞懂這是為什么频蛔,如果哪位大神知道灵迫,請給我留言,謝謝

<style name="AppBaseTheme" parent="@android:style/Theme.DeviceDefault.Light.DarkActionBar"></style>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末晦溪,一起剝皮案震驚了整個(gè)濱河市瀑粥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌三圆,老刑警劉巖狞换,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件避咆,死亡現(xiàn)場離奇詭異,居然都是意外死亡哀澈,警方通過查閱死者的電腦和手機(jī)牌借,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來割按,“玉大人膨报,你說我怎么就攤上這事∈嗜伲” “怎么了现柠?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長弛矛。 經(jīng)常有香客問我够吩,道長,這世上最難降的妖魔是什么丈氓? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任周循,我火速辦了婚禮,結(jié)果婚禮上万俗,老公的妹妹穿的比我還像新娘湾笛。我一直安慰自己,他們只是感情好闰歪,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布嚎研。 她就那樣靜靜地躺著,像睡著了一般库倘。 火紅的嫁衣襯著肌膚如雪临扮。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天教翩,我揣著相機(jī)與錄音杆勇,去河邊找鬼。 笑死饱亿,一個(gè)胖子當(dāng)著我的面吹牛蚜退,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播路捧,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼关霸,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了杰扫?” 一聲冷哼從身側(cè)響起队寇,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎章姓,沒想到半個(gè)月后佳遣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體识埋,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年零渐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了窒舟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,703評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出痰娱,到底是詐尸還是另有隱情但壮,我是刑警寧澤轩猩,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏热监。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一饮寞、第九天 我趴在偏房一處隱蔽的房頂上張望孝扛。 院中可真熱鬧,春花似錦幽崩、人聲如沸苦始。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽盈简。三九已至凑耻,卻和暖如春太示,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背香浩。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工类缤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人邻吭。 一個(gè)月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓餐弱,卻偏偏與公主長得像,于是被迫代替她去往敵國和親囱晴。 傳聞我的和親對象是個(gè)殘疾皇子膏蚓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容