美文网首页刨根究底系列
刨根究底之为何Notification.contentView为

刨根究底之为何Notification.contentView为

作者: 十蛋stan | 来源:发表于2018-12-15 23:12 被阅读64次

    最近适配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为

        本文链接:https://www.haomeiwen.com/subject/cvbohqtx.html