最近适配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里面生成的过程
- 再看看为什么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了.
网友评论