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

最近适配Android8.0遇见这么个问题.
之前为了根据系统主题适配通知栏需要获取默认的Notification.contentView

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

然而Android7.0之后Notification.contentView为空,代码就报空指针异常了.
抱着刨根究底的精神,那我必须探索下为什么为空啊.

先看下contentView是怎么构造的 (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这个名字是不是很激动,

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

调用applyStandardTemplate生成Notification

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

到此为止就发现了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以下的版本才会给你默认生成contentView了.

你可能感兴趣的:(刨根究底之为何Notification.contentView为空)