Android5.0通知變化淺析

目前在Android中通知的使用仍是很常見的,爲了作版本兼容,經常使用兼容包NotificationCompat.Builder和 Notification.Builder。html

  • NotificationCompat.Builder位於v4擴展包內(version 4 Support Library)
  • Notification.Builder在Android 3.0 開始引入(API level 11).

最近在Android5.0設備上發現一個問題:通知圖標忽然變成了白色的方塊而不是代碼中設置的icon。java

問題緣由

細讀開發者文檔其實也能夠發現一些線索,雖然筆者是直接查的源碼發現的問題緣由。http://developer.android.com/design/patterns/notifications.html 一文的Use distinct icons部分介紹了幾點關於通知的建議,其中的有兩點是建議開發者不要作的行爲。android

Don't
Place any additional alpha (dimming or fading) into your small icons and action icons; they can have anti-aliased edges, but because Android uses these icons as masks (that is, only the alpha channel is used), the image should generally be drawn at full opacity.

Don't
Use color to distinguish your app from others. Notification icons should only be a white-on-transparent background image.

簡單的說就是5.0後Android官方建議不要爲通知的圖標添加任何額外的透明度,漸變色,不要企圖用顏色將通知圖標與其餘應用,好比系統應用,應用的通知圖標只能是在透明的背景上有白色的圖案。
至於緣由,文檔並無細說,只是提到5.0系統將會在底層處理圖標,想知怎麼處理的能夠參考Android SDK API level 21後的Notificaiton源碼,裏面寫的較詳細。
Project Structure
Project Structureapi

結合文檔提供的圖片示例,應該能夠理解。
若是不遵循建議那麼有很大概率是會出上文提到問題的,爲何不是別然出問題呢?
這還依賴於代碼編譯的版本,根據嘗試,目前api 21之後編譯會出問題,20及之前的版本編譯不會出問題。因此解決問題比較簡單粗暴的方案是用20及更早的版本編譯代碼。可是要測底解決問題,仍是得遵循文檔指導,及重新設計通知的圖標以符合要求。app

源碼分析

下面看一下到底21的Android源碼裏面作了什麼操做會致使通知的圖標通通變白色。
Notification.javaide

private RemoteViews applyStandardTemplate(int resId, boolean hasProgress) {
    //...
    if (mLargeIcon != null) {
         contentView.setImageViewBitmap(R.id.icon, mLargeIcon);
         processLargeLegacyIcon(mLargeIcon, contentView);
         contentView.setImageViewResource(R.id.right_icon, mSmallIcon);
         contentView.setViewVisibility(R.id.right_icon, View.VISIBLE);
         processSmallRightIcon(mSmallIcon, contentView);
     } else { // small icon at left
         contentView.setImageViewResource(R.id.icon, mSmallIcon);
         contentView.setViewVisibility(R.id.icon, View.VISIBLE);
         processSmallIconAsLarge(mSmallIcon, contentView);
    }
    //...
}
/**
         * Recolor small icons when used in the R.id.right_icon slot.
         */
        private void processSmallRightIcon(int smallIconDrawableId,
                RemoteViews contentView) {
            if (!isLegacy() || mColorUtil.isGrayscaleIcon(mContext, smallIconDrawableId)) {
                contentView.setDrawableParameters(R.id.right_icon, false, -1,
                        0xFFFFFFFF,
                        PorterDuff.Mode.SRC_ATOP, -1);

                contentView.setInt(R.id.right_icon,
                        "setBackgroundResource",
                        R.drawable.notification_icon_legacy_bg);

                contentView.setDrawableParameters(
                        R.id.right_icon,
                        true,
                        -1,
                        resolveColor(),
                        PorterDuff.Mode.SRC_ATOP,
                        -1);
            }
        }

這裏我截取了兩段比較關鍵的代碼,在用NotificationCompat.Builder實例化咱們的通知後,最終須要將各類圖標,參數配置,應用到通知視圖上面。能夠看到若是咱們只設置smallIcon而不設置largeIcon也是能夠的,此時直接將small做爲大圖標設置給左側的id爲R.id.icon的ImageView。要注意的事通常狀況下都不能夠不設置smallIcon,不然通知沒法正常顯示出來。
processSmallIconAsLarge方法裏面負責將咱們設置的smallIcon二次處理,也就是這裏會改變咱們最終看到的通知圖標,包括頂部狀態欄和下拉顯示的小圖標。源碼分析

參考

  1. http://developer.android.com/design/patterns/notifications.html
  2. http://developer.android.com/guide/topics/ui/notifiers/notifications.html
相關文章
相關標籤/搜索