最近適配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里面生成的過程
- 再看看為什么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了.