Android中关于Notification及NotificationManger的详解(android notificationmanager)
25-01-26
20
对于Android中关于Notification及NotificationManger的详解感兴趣的读者,本文将会是一篇不错的选择,我们将详细介绍androidnotificationmanager,
对于Android中关于Notification及NotificationManger的详解 感兴趣的读者,本文将会是一篇不错的选择,我们将详细介绍android notificationmanager ,并为您提供关于Android Notification、Android Notification 从 notify 到添加 view 的处理流程、Android Notification 使用方法详解、android Notification 的一个简单应用(在 Notification 中嵌入一个进度条,并且这个 Notification 点击消失但不会跳转) 的有用信息。
本文目录一览:
Android中关于Notification及NotificationManger的详解(android notificationmanager) Android状态栏提醒
在Android中提醒功能也可以用AlertDialog,但是我们要慎重的使用,因为当使用AlertDialog的时候,用户正在进行的操作将会被打断,因为当前焦点被AlertDialog得到。我们可以想像一下,当用户打游戏正爽的时候,这时候来了一条短信。如果这时候短信用AlertDialog提醒,用户必须先去处理这条提醒,从而才能继续游戏。用户可能会活活被气死。而使用Notification就不会带来这些麻烦事,用户完全可以打完游戏再去看这条短信。所以在开发中应根据实际需求,选择合适的控件。
步骤:
一、添加布局对象
<Button android:id="@+id/showButton" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="showNotification" />
<Button android:id="@+id/cancelButton" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="cancelNotification" />
二、修改MianActivity继承处Activity并实现接口OnClickListener public class MainActivity extends Activity implements OnClickListener { private Context mContext = this; private Button showbtn,calclebtn; private Notification noti; private notificationmanager notimanger; private static int NOTIFICATION_ID = 0x0001;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setUpViews(); }
private void setUpViews() { showbtn = (Button) findViewById(R.id.showButton); calclebtn = (Button) findViewById(R.id.cancelButton); noti = new Notification(R.drawable.ic_launcher,"this is a notification",System.currentTimeMillis()); noti.defaults = Notification.DEFAULT_SOUND;// 使用默认的提示声音 noti.defaults |= Notification.DEFAULT_VIBRATE;// 添加震动 notimanger = (notificationmanager) this.getSystemService(mContext.NOTIFICATION_SERVICE);//获取Nofificationmanger对象 showbtn.setonClickListener(this);//让Activity实现接口OnClickListener可以简单的通过此两行代码添加按钮点击响应事件 calclebtn.setonClickListener(this); }
// 按钮点击事件响应 @Override public void onClick(View v) { if (v == showbtn) { Intent intent = new Intent(this.getApplicationContext(),this.getClass()); // 设置Intent.FLAG_ACTIVITY_NEW_TASK intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent contentIntent = PendingIntent.getActivity(this,intent,0); // noti.setLatestEventInfo(context,contentTitle,contentText,contentIntent)设置(上下文,标题,内容,PendingInteng) noti.setLatestEventInfo(this,"10086","你从此以后免除所有话费",contentIntent); // 发送通知(消息ID,通知对象) notimanger.notify(NOTIFICATION_ID,noti); } else if (v == calclebtn) { // 取消通知(id) notimanger.cancel(NOTIFICATION_ID); } } }
Android Notification 请教一下,如何定义一个按键,当按下的时候弹出系统的Notification通知?急等...
Android Notification 从 notify 到添加 view 的处理流程 创建 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 ------------
@Override public 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 { 1 NotificationListenerService 是个抽象方法,那很自然调用的时候会调用它的子类, 然后
public class NotificationListenerWithPlugins extends NotificationListenerService 1 但是找了一圈 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
@Override protected 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); }
Android Notification 使用方法详解 Android Notification 使用方法详解
用TaskStackBuilder来获取PendingIntent处理点击跳转到别的Activity,首先是用一般的PendingIntent来进行跳转。
mBuilder = new NotificationCompat.Builder(this).setContent(view)
.setSmallIcon(R.drawable.icon).setTicker("新资讯")
.setWhen(System.currentTimeMillis())
.setongoing(false)
.setAutoCancel(true);
Intent intent = new Intent(this,NotificationShow.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,intent,PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(pendingIntent);
直接用PendingIntent来跳转到NotificationShow,在运行效果上来看,首先发送了一条Notification到通知栏上,然后这时,我退出程序,即MainActivity已经不存在了,回到home主菜单,看到Notification仍然存在,当然,我们还没有点击或者cancel它,现在去点击Notification,跳转到NotificationShow界面,然后我们按下Back键,发现直接回到主界面了。现在大多数android应用都是在通知栏中如果有Notification通知的话,点击它,然后会直接跳转到对应的应用程序的某个界面,这时如果回退,即按下Back键,会返回到该应用程序的主界面,而不是系统的主界面。所以用上面这种PendingIntent的做法达不到目的。这里我们使用TaskStackBuilder来做。
mBuilder = new NotificationCompat.Builder(this).setContent(view)
.setSmallIcon(R.drawable.icon).setTicker("新资讯")
.setWhen(System.currentTimeMillis())
.setongoing(false)
.setAutoCancel(true);
Intent intent = new Intent(this,NotificationShow.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(NotificationShow.class);
stackBuilder.addNextIntent(intent);
PendingIntent pendingIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
// PendingIntent pendingIntent = PendingIntent.getActivity(this,// intent,PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(pendingIntent);
显示用TaskStackBuilder.create(this)一个stackBuilder实例,接下来addParentStack();关于这个方法,我们查一下官方api文档:Add the activity parent chain as specified by the parentActivityName attribute of the activity (or activity-alias) element in the application's manifest to the task stack builder. 这句话是说添加一个activity,与这个activity的manifest文件中的parentActivityName的属性相关联。
那么我们就在manifest文件中添加这个属性
<activity
android:name="com.shulf.notificationtest.NotificationShow"
android:parentActivityName=".MainActivity" >
</activity>
让它的parentActivity为MainActivity,也就是说在NotificationShow这个界面点击回退时,会跳转到MainActivity这个界面,而不是像上面一样直接回到了程序的主菜单。运行一下,最后效果确实是这样。
以上实用Android Notification的实例详解,如有疑问请留言或者到本站社区交流讨论,本站关于Android开发的文章还有很多,希望大家搜出查阅,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
android Notification 的一个简单应用(在 Notification 中嵌入一个进度条,并且这个 Notification 点击消失但不会跳转) 网上很多的例子都是直接获取 Notification 对象来设置一个通知,其实 Notification 跟 Dialog 一样,也有自己的 Builder,可以用 builder 对象来设置一个 Notification
这个例子是在 Notification 中嵌入一个进度条,并且这个 Notification 点击消失但不会跳转(跟 android 的 vcard 文件导入时弹出的 Notification 一样)
NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); Notification.Builder builder = new Notification.Builder(context); builder.setOngoing(true); builder.setProgress (total, current, false);// 设置进度条,false 表示是进度条,true 表示是个走马灯 builder.setTicker (title);// 设置 title builder.setWhen(System.currentTimeMillis()); builder.setContentTitle (content);// 设置内容 builder.setAutoCancel (true);// 点击消失 builder.setSmallIcon(R.drawable.upload); builder.setContentIntent (PendingIntent.getActivity (context, 0, new Intent (), 0));// 这句和点击消失那句是 “Notification 点击消失但不会跳转” 的必须条件,如果只有点击消失那句,这个功能是不能实现的
Notification noti = builder.getNotification(); mNotificationManager.notify(id,noti);
希望这个例子对其他人有点用,因为我特曾为这个功能苦恼过,呵呵!
今天关于Android中关于Notification及NotificationManger的详解 和android notificationmanager 的介绍到此结束,谢谢您的阅读,有关Android Notification、Android Notification 从 notify 到添加 view 的处理流程、Android Notification 使用方法详解、android Notification 的一个简单应用(在 Notification 中嵌入一个进度条,并且这个 Notification 点击消失但不会跳转) 等更多相关知识的信息可以在本站进行查询。