刨根究底之為何Notification.contentView為空

最近適配Android8.0遇見這么個(gè)問題.
之前為了根據(jù)系統(tǒng)主題適配通知欄需要獲取默認(rèn)的Notification.contentView

Notification notification = new NotificationCompat.Builder(context).build();
int layoutId = notification.contentView.getLayoutId();

然而Android7.0之后Notification.contentView為空,代碼就報(bào)空指針異常了.
抱著刨根究底的精神,那我必須探索下為什么為空啊.

先看下contentView是怎么構(gòu)造的 (api-21)

這里是通過NotificationCompat.Builder.build()建立的Notification.

NotificationCompat.Builder:
    public Notification build() {
        return IMPL.build(this);
    }

原來是通過IMPL去build的

NotificationCompat:
    static {
        if (Build.VERSION.SDK_INT >= 21) {
            IMPL = new NotificationCompatImplApi21();
        } else if (Build.VERSION.SDK_INT >= 20) {
            IMPL = new NotificationCompatImplApi20();
        } else if (Build.VERSION.SDK_INT >= 19) {
            IMPL = new NotificationCompatImplKitKat();
        } else if (Build.VERSION.SDK_INT >= 16) {
            IMPL = new NotificationCompatImplJellybean();
        } else if (Build.VERSION.SDK_INT >= 14) {
            IMPL = new NotificationCompatImplIceCreamSandwich();
        } else if (Build.VERSION.SDK_INT >= 11) {
            IMPL = new NotificationCompatImplHoneycomb();
        } else if (Build.VERSION.SDK_INT >= 9) {
            IMPL = new NotificationCompatImplGingerbread();
        } else {
            IMPL = new NotificationCompatImplBase();
        }
    }

先來看看NotificationCompatImplApi21

NotificationCompatImplApi21
        private Notification.Builder b;

        public Builder(Context context, Notification n,...) {
            b = new Notification.Builder(context)
                    .setWhen(n.when)
                    ...
        }
        @Override
        public Notification build() {
            return b.build();
        }

這里b的值就是Notification.Builder().所以b.build()就是Notification.Builder.build()

Notification:
          public Notification build() {
            mOriginatingUserId = mContext.getUserId();
            mHasThreeLines = hasThreeLines();
            //這里生成Notification
            Notification n = buildUnstyled();

            if (mStyle != null) {
                n = mStyle.buildStyled(n);
            }

            if (mExtras != null) {
                n.extras.putAll(mExtras);
            }

            if (mRebuildBundle.size() > 0) {
                n.extras.putAll(mRebuildBundle);
                mRebuildBundle.clear();
            }

            populateExtras(n.extras);
            if (mStyle != null) {
                mStyle.addExtras(n.extras);
            }

            mHasThreeLines = false;
            return n;
        }

通過buildUnstyled生成Notification

          public Notification buildUnstyled() {
            Notification n = new Notification();
            ...
            setBuilderContentView(n, makeContentView());
            ...
          }

看到makeContentView這個(gè)名字是不是很激動(dòng),

        private RemoteViews makeContentView() {
            if (mContentView != null) {
                return mContentView;
            } else {
                return applyStandardTemplate(getBaseLayoutResource());
            }
        }

調(diào)用applyStandardTemplate生成Notification

        private RemoteViews applyStandardTemplate(int resId, boolean hasProgress) {
            RemoteViews contentView = new BuilderRemoteViews(mContext.getApplicationInfo(), resId);
            ...
            return contentView;
        }

到此為止就發(fā)現(xiàn)了contentView在Notification里面生成的過程

  1. 再看看為什么7.0contentView為空
api-24
Notification.Builder:
        public Notification build() {
            ...
            if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N
                    && (mStyle == null || !mStyle.displayCustomViewInline())) {
                if (mN.contentView == null) {
                    mN.contentView = createContentView();
                    mN.extras.putInt(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT,
                            mN.contentView.getSequenceNumber());
                }
                if (mN.bigContentView == null) {
                    mN.bigContentView = createBigContentView();
                    if (mN.bigContentView != null) {
                        mN.extras.putInt(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT,
                                mN.bigContentView.getSequenceNumber());
                    }
                }
                if (mN.headsUpContentView == null) {
                    mN.headsUpContentView = createHeadsUpContentView();
                    if (mN.headsUpContentView != null) {
                        mN.extras.putInt(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT,
                                mN.headsUpContentView.getSequenceNumber());
                    }
                }
            }
            ...
            return mN;
        }

這里做了判斷mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N.也就是說target是6.0以下的版本才會(huì)給你默認(rèn)生成contentView了.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容