赞
踩
SystemUI
中的四种通知视图在 Android 系统中,通知可以具有不同的视图来显示信息,这些视图在不同的上下文和设备状态下有不同的显示方式。以下是 Android 13 的 SystemUI 上定义的四种主要的通知视图:
content view
)
expanded view
)
heads up view
)
public view
)
SystemUI
源码中对通知视图的标志(flag
)定义flag
)在 SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
中有上述四种的通知视图的标志(flag
)定义。源码如下(本文基于 android_13.0.0_r1
的 SystemUI
源码讲解):
@Retention(RetentionPolicy.SOURCE) @IntDef(flag = true, prefix = {"FLAG_CONTENT_VIEW_"}, value = { FLAG_CONTENT_VIEW_CONTRACTED, FLAG_CONTENT_VIEW_EXPANDED, FLAG_CONTENT_VIEW_HEADS_UP, FLAG_CONTENT_VIEW_PUBLIC, FLAG_CONTENT_VIEW_ALL}) @interface InflationFlag {} /** * The default, contracted view. Seen when the shade is pulled down and in the lock screen * if there is no worry about content sensitivity. * 默认视图,代表折叠后的最小化视图。当通知栏被下拉时,以及在锁屏上(如果内容不敏感)时显示这个视图 */ int FLAG_CONTENT_VIEW_CONTRACTED = 1; /** * The expanded view. Seen when the user expands a notification. * 扩展视图,当用户点击或以其他方式展开一个通知时显示 */ int FLAG_CONTENT_VIEW_EXPANDED = 1 << 1; /** * The heads up view. Seen when a high priority notification peeks in from the top. * 弹出视图(Heads Up),用于显示高优先级通知的预览,这些通知从屏幕顶部弹出 */ int FLAG_CONTENT_VIEW_HEADS_UP = 1 << 2; /** * The public view. This is a version of the contracted view that hides sensitive * information and is used on the lock screen if we determine that the notification's * content should be hidden. * 公共视图,是折叠视图的一个版本,它隐藏了敏感信息,在锁屏上用于显示如果我们确定通知的内容应该被隐藏 */ int FLAG_CONTENT_VIEW_PUBLIC = 1 << 3; // 这是一个特殊的标志,用来表示所有视图类型。它通过计算 (1 << 4) 得到16,然后减去1得到15, // 这是因为前四个标志分别是1, 2, 4, 和 8,其按位组合结果为15 int FLAG_CONTENT_VIEW_ALL = (1 << 4) - 1;
FLAG_CONTENT_VIEW_CONTRACTED
= 1 (0001
, 二进制)FLAG_CONTENT_VIEW_EXPANDED
= 2 (0010
)FLAG_CONTENT_VIEW_HEADS_UP
= 4 (0100
)FLAG_CONTENT_VIEW_PUBLIC
= 8 (1000
)FLAG_CONTENT_VIEW_ALL
= 15 (1111
,这个是特殊的标志,用于一些处理逻辑上)NotificationContentInflater # InflationProgress
SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
的静态内部类 InflationProgress
是通知视图加载、填充(inflate
)过程中会用到的数据类,它指定了需要填充的通知视图和相关的UI数据。它的成员变量中包含了这四种通知视图类型对应的的数据结构(RemoteViews
)和控件(View
)。
@VisibleForTesting static class InflationProgress { private RemoteViews newContentView; // 通知的默认的折叠视图布局 private RemoteViews newHeadsUpView; // 通知的弹出视图布局 private RemoteViews newExpandedView; // 通知的扩展视图布局 private RemoteViews newPublicView; // 通知的公共视图布局 @VisibleForTesting Context packageContext; private View inflatedContentView; // 已填充的默认的折叠视图 private View inflatedHeadsUpView; // 已填充的弹出视图 private View inflatedExpandedView; // 已填充的扩展视图 private View inflatedPublicView; // 已填充的公共视图 private CharSequence headsUpStatusBarText; private CharSequence headsUpStatusBarTextPublic; private InflatedSmartReplyState inflatedSmartReplyState; private InflatedSmartReplyViewHolder expandedInflatedSmartReplies; private InflatedSmartReplyViewHolder headsUpInflatedSmartReplies; }
RemoteViews
和 View
两者都与通知视图相关,但它们在通知内容填充(inflation
)过程中扮演着不同的角色:
RemoteViews
:
View
:
简而言之,RemoteViews
是定义通知外观的布局模板(RemoteViews
),而 View
是根据这个模板创建的实际可交互的控件。
@Override protected void executeStage( @NonNull NotificationEntry entry, @NonNull ExpandableNotificationRow row, @NonNull StageCallback callback) { RowContentBindParams params = getStageParams(entry); ... // Resolve content to bind/unbind. @InflationFlag int inflationFlags = params.getContentViews(); @InflationFlag int invalidatedFlags = params.getDirtyContentViews(); @InflationFlag int contentToBind = invalidatedFlags & inflationFlags; @InflationFlag int contentToUnbind = inflationFlags ^ FLAG_CONTENT_VIEW_ALL; // Bind/unbind with parameters mBinder.unbindContent(entry, row, contentToUnbind); ... mBinder.bindContent(entry, row, contentToBind, bindParams, forceInflate, inflationCallback); }
inflationFlags
: 表示当前要显示的视图。如 inflationFlags
= 1101
(二进制),这表示折叠视图、弹出视图和公共视图要显示。invalidatedFlags
:表示需要更新的视图。如 invalidatedFlags
= 1011
(二进制),这表示折叠视图、扩展视图和公共视图要更新。contentToBind
:只有需要更新并且要显示的视图才是要绑定的视图集合。 如 contentToBind
经过下面的相与后得到 1001
,表示折叠视图和公共视图要绑定。inflationFlags: 1101
invalidatedFlags: 1011
----
contentToBind: 1001
contentToUnbind
: 表示需要解绑的视图。FLAG_CONTENT_VIEW_ALL
= 1111
代表所有视图的集合。inflationFlags
与 FLAG_CONTENT_VIEW_ALL
的异或得到的结果是不需要显示的视图,即需要解绑的的视图。inflationFlags: 0110 (展开和头部弹出的视图需要显示)
FLAG_CONTENT_VIEW_ALL: 1111 (所有视图)
----
contentToUnbind: 1001
mBinder.bindContent(entry, row, contentToBind, bindParams, forceInflate, inflationCallback);
这段代码。类 NotificationContentInflater
的方法 bindContent
是 mBinder.bindContent()
的具体实现@Override public void bindContent( NotificationEntry entry, ExpandableNotificationRow row, @InflationFlag int contentToBind, BindParams bindParams, boolean forceInflate, @Nullable InflationCallback callback) { ... // Cancel any pending frees on any view we're trying to bind since we should be bound after. cancelContentViewFrees(row, contentToBind); AsyncInflationTask task = new AsyncInflationTask( mBgExecutor, mInflateSynchronously, contentToBind, mRemoteViewCache, entry, mConversationProcessor, row, bindParams.isLowPriority, bindParams.usesIncreasedHeight, bindParams.usesIncreasedHeadsUpHeight, callback, mRemoteInputManager.getRemoteViewsOnClickHandler(), mIsMediaInQS, mSmartReplyStateInflater); if (mInflateSynchronously) { task.onPostExecute(task.doInBackground()); } else { task.executeOnExecutor(mBgExecutor); } }
contentToBind
传入到 类 NotificationContentInflater
的静态内部类 AsyncInflationTask
的构造方法里,被赋值给类 AsyncInflationTask
中的成员变量 mReInflateFlags
。private AsyncInflationTask( Executor bgExecutor, boolean inflateSynchronously, @InflationFlag int reInflateFlags, NotifRemoteViewCache cache, NotificationEntry entry, ConversationNotificationProcessor conversationProcessor, ExpandableNotificationRow row, boolean isLowPriority, boolean usesIncreasedHeight, boolean usesIncreasedHeadsUpHeight, InflationCallback callback, RemoteViews.InteractionHandler remoteViewClickHandler, boolean isMediaFlagEnabled, SmartReplyStateInflater smartRepliesInflater) { ... mReInflateFlags = reInflateFlags; ... }
task.doInBackground()
这段代码,它里面用到了 内部类 AsyncInflationTask
的成员变量 mReInflateFlags
。 mReInflateFlags
传入到 方法 createRemoteViews
和 inflateSmartReplyViews
中作为参数。@Override protected InflationProgress doInBackground(Void... params) { try { ... InflationProgress inflationProgress = createRemoteViews(mReInflateFlags, recoveredBuilder, mIsLowPriority, mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight, packageContext); InflatedSmartReplyState previousSmartReplyState = mRow.getExistingSmartReplyState(); return inflateSmartReplyViews( inflationProgress, mReInflateFlags, mEntry, mContext, packageContext, previousSmartReplyState, mSmartRepliesInflater); } catch (Exception e) { mError = e; return null; } }
方法 createRemoteViews
根据给定的标志创建通知的 RemoteViews
对象,这些对象代表了通知在状态栏、锁屏等地方显示的不同视图(例如,折叠视图、展开视图、弹出视图和公共视图)。
reInflateFlags
判断是否包含某些通知视图,如果包含,则构建相应的通知视图的数据结构(RemoteViews
), 并赋值给 InflationProgress
实例的对应的通知视图的RemoteView
成员变量。private static InflationProgress createRemoteViews(@InflationFlag int reInflateFlags, Notification.Builder builder, boolean isLowPriority, boolean usesIncreasedHeight, boolean usesIncreasedHeadsUpHeight, Context packageContext) { InflationProgress result = new InflationProgress(); if ((reInflateFlags & FLAG_CONTENT_VIEW_CONTRACTED) != 0) { result.newContentView = createContentView(builder, isLowPriority, usesIncreasedHeight); } if ((reInflateFlags & FLAG_CONTENT_VIEW_EXPANDED) != 0) { result.newExpandedView = createExpandedView(builder, isLowPriority); } if ((reInflateFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0) { result.newHeadsUpView = builder.createHeadsUpContentView(usesIncreasedHeadsUpHeight); } if ((reInflateFlags & FLAG_CONTENT_VIEW_PUBLIC) != 0) { result.newPublicView = builder.makePublicContentView(isLowPriority); } result.packageContext = packageContext; result.headsUpStatusBarText = builder.getHeadsUpStatusBarText(false /* showingPublic */); result.headsUpStatusBarTextPublic = builder.getHeadsUpStatusBarText( true /* showingPublic */); return result; }
inflateSmartReplyViews
方法是 Android 系统 UI 组件中处理通知行(ExpandableNotificationRow
)智能回复视图填充(inflate
)的一个辅助方法。这个方法的目的是为了根据通知的内容,异步地构建并且填充与智能回复相关的视图。private static InflationProgress inflateSmartReplyViews( InflationProgress result, @InflationFlag int reInflateFlags, NotificationEntry entry, Context context, Context packageContext, InflatedSmartReplyState previousSmartReplyState, SmartReplyStateInflater inflater) { boolean inflateContracted = (reInflateFlags & FLAG_CONTENT_VIEW_CONTRACTED) != 0 && result.newContentView != null; boolean inflateExpanded = (reInflateFlags & FLAG_CONTENT_VIEW_EXPANDED) != 0 && result.newExpandedView != null; boolean inflateHeadsUp = (reInflateFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0 && result.newHeadsUpView != null; if (inflateContracted || inflateExpanded || inflateHeadsUp) { result.inflatedSmartReplyState = inflater.inflateSmartReplyState(entry); } if (inflateExpanded) { result.expandedInflatedSmartReplies = inflater.inflateSmartReplyViewHolder( context, packageContext, entry, previousSmartReplyState, result.inflatedSmartReplyState); } if (inflateHeadsUp) { result.headsUpInflatedSmartReplies = inflater.inflateSmartReplyViewHolder( context, packageContext, entry, previousSmartReplyState, result.inflatedSmartReplyState); } return result; }
以上就是关于 SystemUI 的加载对应通知视图类型的部分过程。
如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。
如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。
欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓(文末还有ChatGPT机器人小福利哦,大家千万不要错过)
PS:群里还设有ChatGPT机器人,可以解答大家在工作上或者是技术上的问题
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。