Android版本:8.1


创建Notification是很容易的,android8.0以后开始加入通知渠道NotificationChannel,然后在构造NotificationCompat.Builder的时候,指定要发送的渠道,最后调用NotificationManager.notify(id,notification)发送通知。

    public void notify(int id, Notification notification)    {        notify(null, id, notification);    }    ---------------    public void notify(String tag, int id, Notification notification)    {        notifyAsUser(tag, id, notification, new UserHandle(UserHandle.myUserId()));    }    ---------------    public void notifyAsUser(String tag, int id, Notification notification, UserHandle user)    {        INotificationManager service = getService();         final Notification copy = Builder.maybeCloneStrippedForDelivery(notification, isLowRam);         ...        try {            service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,                    copy, user.getIdentifier());        } catch (RemoteException e) {            throw e.rethrowFromSystemServer();        } }   -------------------    static public INotificationManager getService()    {        if (sService != null) {            return sService;        }        IBinder b = ServiceManager.getService("notification");        sService = INotificationManager.Stub.asInterface(b);        return sService;    }

获取了INotificationManager 远程接口对象,把Notification 给加入到队列中,
INotificationManager的远程对象是NotificationManagerService里的mservice,NotificationManagerService是系统服务。在开机启动的时候,Systemserver里和其他系统服务一起启动,最后注册到ServiceManager里。

publishBinderService(Context.NOTIFICATION_SERVICE, mService);  //把service注册到Servicemanager里----private final IBinder mService = new INotificationManager.Stub(){...}

接着前面的,找到了enqueueNotificationWithTag

    @Override    public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,            Notification notification, int userId) throws RemoteException {        enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),                Binder.getCallingPid(), tag, id, notification, userId);    }    ------------    void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,            final int callingPid, final String tag, final int id, final Notification notification,            int incomingUserId) {    ....处理notification包含的信息,通知渠道,优先级。。    mHandler.post(new EnqueueNotificationRunnable(userId, r));}

把notification转换为NotificationRecord,并post给EnqueueNotificationRunnable,

EnqueueNotificationRunnable的run方法里。    @Override    public void run() {        synchronized (mNotificationLock) {            mEnqueuedNotifications.add(r);            scheduleTimeoutLocked(r);            ...            mHandler.post(new PostNotificationRunnable(r.getKey()));        }    ------------    @Override    public void run() {        synchronized (mNotificationLock) {            try {                NotificationRecord r = null;                int N = mEnqueuedNotifications.size();                    NotificationRecord old = mNotificationsByKey.get(key);                final StatusBarNotification n = r.sbn;                final Notification notification = n.getNotification();                      ...                 if (notification.getSmallIcon() != null) {                     StatusBarNotification oldSbn = (old != null) ? old.sbn : null;                     mListeners.notifyPostedLocked(n, oldSbn);                     if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) {                         mHandler.post(new Runnable() {                             @Override                             public void run() {                                 mGroupHelper.onNotificationPosted(                                         n, hasAutoGroupSummaryLocked(n));                             }                         });                     }                }                ...                buzzBeepBlinkLocked(r);               }   ------------  void buzzBeepBlinkLocked(NotificationRecord record) {处理notification的 声音 震动和灯光闪烁  }  ------------  public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {发送给状态栏    mHandler.post(new Runnable() {       @Override       public void run() {           notifyPosted(info, sbnToPost, update);       }   });  }private void notifyPosted(final ManagedServiceInfo info,        final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {    final INotificationListener listener = (INotificationListener) info.service;    StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);    try {        listener.onNotificationPosted(sbnHolder, rankingUpdate);    } catch (RemoteException ex) {        Log.e(TAG, "unable to notify listener (posted): " + listener, ex);    }  }  

INotificationListener是另一个远程接口对象

protected class NotificationListenerWrapper extends INotificationListener.Stub------------@Overridepublic void onNotificationPosted(IStatusBarNotificationHolder sbnHolder,        NotificationRankingUpdate update) {        SomeArgs args = SomeArgs.obtain();        args.arg1 = sbn;        args.arg2 = mRankingMap;        mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_POSTED,                args).sendToTarget();        }case MSG_ON_NOTIFICATION_POSTED: {   SomeArgs args = (SomeArgs) msg.obj;   StatusBarNotification sbn = (StatusBarNotification) args.arg1;   RankingMap rankingMap = (RankingMap) args.arg2;   args.recycle();   onNotificationPosted(sbn, rankingMap);------------public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {    onNotificationPosted(sbn);}public void onNotificationPosted(StatusBarNotification sbn) {    // optional}

很意外,发现方法是空的,那调这么多有什么用? 研究了一下发现,onNotificationPosted的这个方法属于的是

public abstract class NotificationListenerService extends Service {

NotificationListenerService 是个抽象方法,那很自然调用的时候会调用它的子类,
然后

public class NotificationListenerWithPlugins extends NotificationListenerService

但是找了一圈NotificationListenerWithPlugins ,没有onNotificationPosted,那只有继续找它的子类了,
后来发现,在Statusbar里有个匿名内部类实现了NotificationListenerService 的方法。

private final NotificationListenerWithPlugins mNotificationListener =        new NotificationListenerWithPlugins() {...@Override        public void onNotificationPosted(final StatusBarNotification sbn,                final RankingMap rankingMap) {                          mHandler.post(new Runnable() {                  @Override                  public void run() {...if (isUpdate) {                    updateNotification(sbn, rankingMap);                } else {                    addNotification(sbn, rankingMap);                }...}        }        ...}------------    public void addNotification(StatusBarNotification notification, RankingMap ranking)       throws InflationException {        Entry shadeEntry = createNotificationViews(notification);        boolean isHeadsUped = shouldPeek(shadeEntry);.        ...    }------------protected NotificationData.Entry createNotificationViews(StatusBarNotification sbn)        throws InflationException {     NotificationData.Entry entry = new NotificationData.Entry(sbn);    Dependency.get(LeakDetector.class).trackInstance(entry);     entry.createIcons(mContext, sbn);     // Construct the expanded view.     inflateViews(entry, mStackScroller);}------------protected void inflateViews(Entry entry, ViewGroup parent) {      new RowInflaterTask().inflate(mContext, parent, entry,              row -> {                  bindRow(entry, pmUser, sbn, row);                  updateNotification(entry, pmUser, sbn, row);              });}            

最后bindRow就是去构造通知栏的通知View,然后updateNotification就是去显示到状态栏。

private void updateNotification(Entry entry, PackageManager pmUser,     StatusBarNotification sbn, ExpandableNotificationRow row) {...row.updateNotification(entry);}------------public void updateNotification(NotificationData.Entry entry) {    mEntry = entry;    mStatusBarNotification = entry.notification;    mNotificationInflater.inflateNotificationViews();}------------public void inflateNotificationViews() {    inflateNotificationViews(FLAG_REINFLATE_ALL);}------------void inflateNotificationViews(int reInflateFlags) {...    StatusBarNotification sbn = mRow.getEntry().notification;    new AsyncInflationTask(sbn, reInflateFlags, mRow, mIsLowPriority,            mIsChildInGroup, mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight, mRedactAmbient,            mCallback, mRemoteViewClickHandler).execute();}

使用了异步任务AsyncTask去完成布局

AsyncInflationTask@Overrideprotected InflationProgress doInBackground(Void... params) {     return createRemoteViews(mReInflateFlags,     recoveredBuilder, mIsLowPriority, mIsChildInGroup,     mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight, mRedactAmbient,     packageContext);}------------private static InflationProgress createRemoteViews(int reInflateFlags,            Notification.Builder builder, boolean isLowPriority, boolean isChildInGroup,            boolean usesIncreasedHeight, boolean usesIncreasedHeadsUpHeight, boolean redactAmbient,            Context packageContext) {        InflationProgress result = new InflationProgress();        isLowPriority = isLowPriority && !isChildInGroup;        if ((reInflateFlags & FLAG_REINFLATE_CONTENT_VIEW) != 0) {            result.newContentView = createContentView(builder, isLowPriority, usesIncreasedHeight);        }        if ((reInflateFlags & FLAG_REINFLATE_EXPANDED_VIEW) != 0) {            result.newExpandedView = createExpandedView(builder, isLowPriority);        }        if ((reInflateFlags & FLAG_REINFLATE_HEADS_UP_VIEW) != 0) {            result.newHeadsUpView = builder.createHeadsUpContentView(usesIncreasedHeadsUpHeight);        }        if ((reInflateFlags & FLAG_REINFLATE_PUBLIC_VIEW) != 0) {            result.newPublicView = builder.makePublicContentView();        }        if ((reInflateFlags & FLAG_REINFLATE_AMBIENT_VIEW) != 0) {            result.newAmbientView = redactAmbient ? builder.makePublicAmbientNotification()                    : builder.makeAmbientNotification();        }        result.packageContext = packageContext;        return result;    }  

到了这里,都是创建各种布局
比如createContentView

public RemoteViews createContentView() {    return createContentView(false /* increasedheight */ );}------------public RemoteViews createContentView(boolean increasedHeight) {    if (mN.contentView != null && useExistingRemoteView()) {        return mN.contentView;    } else if (mStyle != null) {        final RemoteViews styleView = mStyle.makeContentView(increasedHeight);        if (styleView != null) {            return styleView;        }    }    return applyStandardTemplate(getBaseLayoutResource());}

这里会去判断我们是否有在notification里添加style, 如果有不同的style,比如音乐播放器那种notification,就是自定义style,如果没有,那就用默认的layout。

private int getBaseLayoutResource() {    return R.layout.notification_template_material_base;}------------<FrameLayout    xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/status_bar_latest_event_content"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:tag="base" >    <include layout="@layout/notification_template_header" />    <LinearLayout        android:id="@+id/notification_main_column"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_gravity="top"        android:layout_marginStart="@dimen/notification_content_margin_start"        android:layout_marginEnd="@dimen/notification_content_margin_end"        android:layout_marginTop="@dimen/notification_content_margin_top"        android:layout_marginBottom="@dimen/notification_content_margin_bottom"        android:orientation="vertical" >        <include layout="@layout/notification_template_part_line1" />        <include layout="@layout/notification_template_text" />        <include            android:layout_width="match_parent"            android:layout_height="@dimen/notification_progress_bar_height"            android:layout_marginTop="@dimen/notification_progress_margin_top"            layout="@layout/notification_template_progress" />    </LinearLayout>    <include layout="@layout/notification_template_right_icon" /></FrameLayout>

原来这就是我们用的notification的布局内容。

private RemoteViews applyStandardTemplate(int resId) {    return applyStandardTemplate(resId, mParams.reset().fillTextsFrom(this));}private RemoteViews applyStandardTemplate(int resId, boolean hasProgress) {    return applyStandardTemplate(resId, mParams.reset().hasProgress(hasProgress)            .fillTextsFrom(this));}private RemoteViews applyStandardTemplate(int resId, StandardTemplateParams p) {updateBackgroundColor(contentView);    bindNotificationHeader(contentView, p.ambient);    bindLargeIcon(contentView);}

^_^ 后面全是布局绘画.

基本上这就是Notification从app到Framework再到SystemUI的流程,从notify到布局。

更多相关文章

  1. Android::整理基础之—— startActivityForResult相关
  2. Android(安卓)资料整理
  3. Android关于获取时间的记录(小结)
  4. Android(安卓)studio里Toast,menu的用法
  5. Android(安卓)WebView加载网页,实现前进、后退、刷新、超链接
  6. Android(安卓)之 ListView使用SimpleAdapter展示列表
  7. Android(安卓)GestureDetector详解
  8. Android(安卓)时间显示问题
  9. android第一天:搭建基础环境

随机推荐

  1. Android(安卓)标签 (FlexboxLayout实现标
  2. Android(安卓)创建文件电脑端不显示
  3. Android(安卓)自定义ProgressDialog
  4. android 1.5~2.2源码下载
  5. Android(安卓)USB转 串口
  6. rk3288 7.1去掉桌面搜索框
  7. Android(安卓)通过 IMSI 判断手机运营商
  8. android ANR 案例分析
  9. android 4.0 屏蔽home键实现
  10. android jbox2d学习笔记一 滑轮关节