当前位置: 首页 > news >正文

宁津网站建设/全球搜钻是什么公司

宁津网站建设,全球搜钻是什么公司,做电脑游戏破解的网站,上海有哪些公司名字叫什么前言 应用发送一个显示在状态栏上的通知,对于移动设备来说是很常见的一种功能需求,本篇文章我们将会结合Android9.0系统源码具体来分析一下,应用调用notificationManager触发通知栏通知的功能的源码流程。 一、应用触发状态栏通知 应用可以…

前言

应用发送一个显示在状态栏上的通知,对于移动设备来说是很常见的一种功能需求,本篇文章我们将会结合Android9.0系统源码具体来分析一下,应用调用notificationManager触发通知栏通知的功能的源码流程。

一、应用触发状态栏通知

应用可以通过调用如下notity方法可以发送一个显示在状态栏上的通知。

    /*** 发送通知(支持8.0+)*/public void nofify() {// 1. Set the notification content - 创建通知基本内容// https://developer.android.google.cn/training/notify-user/build-notification.html#builderNotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID).setSmallIcon(R.drawable.ic_launcher_background).setContentTitle("My notification")// 这是单行//.setContentText("Much longer text that cannot fit one line...")// 这是多行.setStyle(new NotificationCompat.BigTextStyle().bigText("Much longer text that cannot fit one line..." +"Much longer text that cannot fit one line..." +"Much longer text that cannot fit one line...")).setPriority(NotificationCompat.PRIORITY_HIGH).setAutoCancel(true);// 2. Create a channel and set the importance - 8.0后需要设置Channel// https://developer.android.google.cn/training/notify-user/build-notification.html#buildercreateNotificationChannel();// 3. Set the notification's tap action - 创建一些点击事件,比如点击跳转页面// https://developer.android.google.cn/training/notify-user/build-notification.html#click// 4. Show the notification - 展示通知// https://developer.android.google.cn/training/notify-user/build-notification.html#notifyNotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);// 5.调用notificationManager的notify方法// notificationId is a unique int for each notification that you must definenotificationManager.notify((int) System.currentTimeMillis(), builder.build());}private void createNotificationChannel() {// Create the NotificationChannel, but only on API 26+ because// the NotificationChannel class is new and not in the support libraryCharSequence name = getString(R.string.app_name);String description = getString(R.string.app_name);int importance = NotificationManager.IMPORTANCE_HIGH;NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);channel.setDescription(description);// Register the channel with the system; you can't change the importance// or other notification behaviors after thisNotificationManager notificationManager = getSystemService(NotificationManager.class);notificationManager.createNotificationChannel(channel);}

notify方法先是构建Notification对象,然后调用NotificationManager的notify方法发送构建的这个对象。

二、NotificationManager的相关源码

1、NotificationManager的notify方法如下所示:

frameworks/base/core/java/android/app/NotificationManager.java

public class NotificationManager {//如果应用发送了一个相同id的通知,并且没有被取消,它将被更新的信息所取代。public void notify(int id, Notification notification){notify(null, id, notification);}//应用发送了一个相同tag和id的通知,并且没有被取消,它将被更新的信息所取代。   public void notify(String tag, int id, Notification notification){notifyAsUser(tag, id, notification, mContext.getUser());}
}

2、notify方法最终都会进一步调用notifyAsUser。

public class NotificationManager {/*** @hide*/public void notifyAsUser(String tag, int id, Notification notification, UserHandle user){INotificationManager service = getService();String pkg = mContext.getPackageName();// Fix the notification as best we can.Notification.addFieldsFromContext(mContext, notification);...代码省略...}
}

notifyAsUser方法首先获取NotificationManagerService服务,然后调用了Notification的addFieldsFromContext方法。

3、Notification的addFieldsFromContext方法如下所示:

frameworks/base/core/java/android/app/Notification.java

public class Notification implements Parcelable
{public Bundle extras = new Bundle();/*** @hide*/public static final String EXTRA_BUILDER_APPLICATION_INFO = "android.appInfo";/*** @hide*/public static void addFieldsFromContext(Context context, Notification notification) {addFieldsFromContext(context.getApplicationInfo(), notification);}/*** @hide*/public static void addFieldsFromContext(ApplicationInfo ai, Notification notification) {notification.extras.putParcelable(EXTRA_BUILDER_APPLICATION_INFO, ai);}
}

主要是在Notification对象中类型为Bundle的属性变量extras中保存了当前应用所对应的ApplicationInfo对象。

4、继续往下看NotificationManager的notifyAsUser方法

public class NotificationManager {/*** @hide*/public void notifyAsUser(String tag, int id, Notification notification, UserHandle user){INotificationManager service = getService();String pkg = mContext.getPackageName();// Fix the notification as best we can.Notification.addFieldsFromContext(mContext, notification);if (notification.sound != null) {notification.sound = notification.sound.getCanonicalUri();if (StrictMode.vmFileUriExposureEnabled()) {notification.sound.checkFileUriExposed("Notification.sound");}}//通过包名获取对应包名的应用图标设置为通知的小图标fixLegacySmallIcon(notification, pkg);if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {//Android5.1之后,会判断notification是否有small icon,没有则抛出异常if (notification.getSmallIcon() == null) {throw new IllegalArgumentException("Invalid notification (no valid small icon): "+ notification);}}...代码省略...try {service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,copy, user.getIdentifier());} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}
}

会调用fixLegacySmallIcon方法通,过包名获取对应包名的应用图标设置为通知的小图标,在Android5.1之后的版本中,然后会判断notification是否有small icon,如果没有设icon或small icon,用notify方法时会抛出异常,最终会调用NotificationManagerService的enqueueNotificationWithTag方法。

三、NotificationManagerService和发送通知相关的源码

1、NotificationManagerService的enqueueNotificationWithTag方法如下所示。

frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java

public class NotificationManagerService extends SystemService {@Overridepublic 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);}
}

2、enqueueNotificationWithTag方法会继续调用了enqueueNotificationInternal方法,该方法发送通知的核心。

public class NotificationManagerService extends SystemService {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) {if (DBG) {Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id+ " notification=" + notification);}checkCallerIsSystemOrSameApp(pkg);// 校验UIDfinal int userId = ActivityManager.handleIncomingUser(callingPid,callingUid, incomingUserId, true, false, "enqueueNotification", pkg);final UserHandle user = new UserHandle(userId);if (pkg == null || notification == null) {throw new IllegalArgumentException("null not allowed: pkg=" + pkg+ " id=" + id + " notification=" + notification);}// The system can post notifications for any package, let us resolve that.final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);...代码省略...//上面会进行一系列验证,验证之后,会将传递进来的Notification封装成一个StatusBarNotification对象final StatusBarNotification n = new StatusBarNotification(pkg, opPkg, id, tag, notificationUid, callingPid, notification,user, null, System.currentTimeMillis());// 封装NotificationRecord对象final NotificationRecord r = new NotificationRecord(getContext(), n, channel);...代码省略...mHandler.post(new EnqueueNotificationRunnable(userId, r));}
}

enqueueNotificationInternal会进行一些列验证,待验证完成之后,会调用Handler的post方法开启线程,发起异步操作,触发EnqueueNotificationRunnable对象。

3、EnqueueNotificationRunnable对象如下所示。

public class NotificationManagerService extends SystemService {protected class EnqueueNotificationRunnable implements Runnable {private final NotificationRecord r;private final int userId;EnqueueNotificationRunnable(int userId, NotificationRecord r) {this.userId = userId;this.r = r;};@Overridepublic void run() {synchronized (mNotificationLock) {//将当前通知相关的NotificationRecord对象放到集合中mEnqueuedNotifications.add(r);scheduleTimeoutLocked(r);final StatusBarNotification n = r.sbn;if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());//获取是否存在相同的NotificationRecordNotificationRecord old = mNotificationsByKey.get(n.getKey());if (old != null) {// Retain ranking information from previous recordr.copyRankingInformation(old);}final int callingUid = n.getUid();final int callingPid = n.getInitialPid();final Notification notification = n.getNotification();final String pkg = n.getPackageName();final int id = n.getId();final String tag = n.getTag();// Handle grouped notifications and bail out early if we// can to avoid extracting signals.handleGroupedNotificationLocked(r, old, callingUid, callingPid);// if this is a group child, unsnooze parent summaryif (n.isGroup() && notification.isGroupChild()) {mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());}// This conditional is a dirty hack to limit the logging done on//     behalf of the download manager without affecting other apps.if (!pkg.equals("com.android.providers.downloads")|| Log.isLoggable("DownloadManager", Log.VERBOSE)) {int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;if (old != null) {enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;}EventLogTags.writeNotificationEnqueue(callingUid, callingPid,pkg, id, tag, userId, notification.toString(),enqueueStatus);}mRankingHelper.extractSignals(r);// tell the assistant service about the notificationif (mAssistants.isEnabled()) {mAssistants.onNotificationEnqueued(r);//开启延时线程mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),DELAY_FOR_ASSISTANT_TIME);} else {//开启线程mHandler.post(new PostNotificationRunnable(r.getKey()));}}}}}    

NotificationManagerService 的run方法会将当前NotificationRecord存放到类型为ArrayList的mEnqueuedNotifications集合中,最终会再次调用Handler的post方法开启线程,发起异步操作,触发PostNotificationRunnable对象。

4、PostNotificationRunnable对象如下所示。

    protected class PostNotificationRunnable implements Runnable {private final String key;PostNotificationRunnable(String key) {this.key = key;}@Overridepublic void run() {synchronized (mNotificationLock) {try {NotificationRecord r = null;//从类型为ArrayList<NotificationRecord>的mEnqueuedNotifications集合中//取当前key所对应的NotificationRecord对象int N = mEnqueuedNotifications.size();for (int i = 0; i < N; i++) {final NotificationRecord enqueued = mEnqueuedNotifications.get(i);if (Objects.equals(key, enqueued.getKey())) {r = enqueued;break;}}if (r == null) {Slog.i(TAG, "Cannot find enqueued record for key: " + key);return;}r.setHidden(isPackageSuspendedLocked(r));NotificationRecord old = mNotificationsByKey.get(key);final StatusBarNotification n = r.sbn;final Notification notification = n.getNotification();// 判断是否是已经发送过此notificationint index = indexOfNotificationLocked(n.getKey());if (index < 0) {//如果是新发送的notification,就走新增流程.mNotificationList.add(r);mUsageStats.registerPostedByApp(r);r.setInterruptive(isVisuallyInterruptive(null, r));} else {//如果有发送过,就获取已经存在的NtificationRecord,// 后面走更新流程 mStatusBar.updateNotification(r.statusBarKey, n)old = mNotificationList.get(index);mNotificationList.set(index, r);mUsageStats.registerUpdatedByApp(r, old);// Make sure we don't lose the foreground service state.notification.flags |=old.getNotification().flags & FLAG_FOREGROUND_SERVICE;r.isUpdate = true;r.setTextChanged(isVisuallyInterruptive(old, r));}//将当前NotificationRecord对象以StatusBarNotification为键存放到mNotificationsByKey中mNotificationsByKey.put(n.getKey(), r);// Ensure if this is a foreground service that the proper additional// flags are set.if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) {notification.flags |= Notification.FLAG_ONGOING_EVENT| Notification.FLAG_NO_CLEAR;}applyZenModeLocked(r);mRankingHelper.sort(mNotificationList);if (notification.getSmallIcon() != null) {// 如果notification设置了smallIcon,调用所有NotificationListeners的notifyPostedLocked方法,// 通知有新的notification,传入的参数为上面的NotificationRecord对象StatusBarNotification oldSbn = (old != null) ? old.sbn : null;mListeners.notifyPostedLocked(r, old);if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) {mHandler.post(new Runnable() {@Overridepublic void run() {mGroupHelper.onNotificationPosted(n, hasAutoGroupSummaryLocked(n));}});}} else {//移除已经存在的Slog.e(TAG, "Not posting notification without small icon: " + notification);if (old != null && !old.isCanceled) {mListeners.notifyRemovedLocked(r,NotificationListenerService.REASON_ERROR, null);mHandler.post(new Runnable() {@Overridepublic void run() {mGroupHelper.onNotificationRemoved(n);}});}// ATTENTION: in a future release we will bail out here// so that we do not play sounds, show lights, etc. for invalid// notificationsSlog.e(TAG, "WARNING: In a future release this will crash the app: "+ n.getPackageName());}if (!r.isHidden()) {//如果不是隐藏,则触发振动/铃声/呼吸灯buzzBeepBlinkLocked(r);}maybeRecordInterruptionLocked(r);} finally {int N = mEnqueuedNotifications.size();for (int i = 0; i < N; i++) {final NotificationRecord enqueued = mEnqueuedNotifications.get(i);if (Objects.equals(key, enqueued.getKey())) {mEnqueuedNotifications.remove(i);break;}}}}}}
http://www.whsansanxincailiao.cn/news/31955754.html

相关文章:

  • 网站开发体会/宁波seo服务快速推广
  • 安徽哪家公司做网站比较好/广告联盟哪个比较好
  • 网站页脚设计/百度电脑版网页
  • 大连网站开发建站/关键词挖掘机爱站网
  • 网站规划与开发专业/安卓排名优化
  • 400网站建设推广/竞价推广员月挣多少
  • 南京大型门户网站制作/成都seo论坛
  • 网站管理 官网/百度收录规则
  • 网站没完成可以备案么/无锡百度推广开户
  • 公司企业邮箱大全/搜索引擎优化的五个方面
  • 北京建设信息咨询中心网站/定制网站开发
  • 商机互联做的网站和推广怎么样/seo资料
  • 响应式网站做mip/百度seo搜索营销新视角
  • 公司seo排名优化/优化营商环境指什么
  • 绵阳网站建设/品牌策划方案怎么做
  • wordpress本地怎么搬家/汕头seo
  • php网站后台管理模板/网络推广有哪些常见的推广方法
  • 六一儿童节网站制作/现在的网络推广怎么做
  • 上海网站建设宣传/企业推广是做什么的
  • 邢台信息港欢迎您/seo公司的选上海百首网络
  • 网站建设jiage/竞价排名采用什么计费方式
  • 上海网站开发工程师招聘网/西安网站seo厂家
  • 学网站建设工作室/百度云网盘搜索引擎
  • 杂志在线设计网站/百度seo优化规则
  • 培训网站建设方案书/自媒体平台大全
  • 国内外公司网站差异/外链是什么意思
  • 通州网站制作/百度竞价推广开户
  • 行业 网站 方案/1元购买域名
  • 啥是深圳网站建设/千锋教育可靠吗
  • 临海市网站建设/百度点击快速排名