1. 程式人生 > >不同版本Notification的顯示問題(最簡單的方法是把目標版本更改為4.4)

不同版本Notification的顯示問題(最簡單的方法是把目標版本更改為4.4)

目前在Android中通知的使用還是很常見的,為了做版本相容,常用相容包NotificationCompat.Builder和 Notification.Builder。

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

最近在Android5.0裝置上發現一個問題:通知圖示突然變成了白色的方塊而不是程式碼中設定的icon。

問題原因

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 Structure

結合文件提供的圖片示例,應該可以理解。
如果不遵循建議那麼有很大機率是會出上文提到問題的,為什麼不是別然出問題呢?
這還依賴於程式碼編譯的版本,根據嘗試,目前api 21以後編譯會出問題,20及以前的版本編譯不會出問題。所以解決問題比較簡單粗暴的方案是用20及更早的版本編譯程式碼。但是要測底解決問題,還是得遵循文件指導,及從新設計通知的圖示以符合要求。

原始碼分析

下面看一下到底21的Android原始碼裡面做了什麼操作會導致通知的圖示統統變白色。
Notification.java

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二次處理,也就是這裡會改變我們最終看到的通知圖示,包括頂部狀態列和下拉顯示的小圖示。

參考