Android(安卓)Notification点击按钮改变内容方案
最近做项目的时候,遇到一个需求:发送一个带加减按钮和一个数字的通知,点击按钮后,通知的数字相应的要改变。
听起来很简单,不就是给两个按钮添加点击事件就可以了吗。可是,通知并不属于App的进程,而是Android系统维护的进程,我们在通知里面自定义的布局要通过RemoteViews
来实现:
RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.layout_number);NotificationCompat.Builder.setContent(remoteViews);
RemoteViews
是用来处理跨进程显示的布局方案,一般用于通知和桌面小部件。由于进程的不同,所以RemoteViews
所应用的布局并不能直接使用findViewById()
来查找控件,它封装了一些方法来更新UI
,例如:
void setTextViewText(int viewId, CharSequence text);void setViewVisibility(int viewId, int visibility);void setProgressBar(int viewId, int max, int progress, boolean indeterminate);void setImageViewResource(int viewId, int srcId);
更多方法可以参考官方Api文档
它没有提供直接给控件添加点击事件的方法。所以遇到了困境。
那么可不可以直接将整个通知的布局写成自定义控件,把按钮的点击在自定义控件里面实现呢?很遗憾是不可以的,当发送通知时,会直接报下列的错误:
android.app.RemoteServiceException: Bad notification posted from package com.example.xujiafeng.notificationrefresh
其实仔细想想也很正常,如果能这么简单的设置点击事件,RemoteViews
不可能不暴露给控件设置点击事件的方法给我们。
那么还有什么办法呢?
RemoteViews
虽然没有直接给控件设置点击事件的方法,可是提供了以下方法:
void setOnClickPendingIntent (int viewId, PendingIntent pendingIntent)
官方文档对这个方法的解释是:相当于调用
setOnClickListener(android.view.View.OnClickListener)
来启动提供的PendingIntent
。
而PendingIntent
是一个延时Intent
,它内部包含了一个Intent
,当某种条件满足时他才会启动Intent
,它有四个方法来获取对象:
getActivity(Context, int, Intent, int);getActivities(Context, int, Intent[], int);getBroadcast(Context, int, Intent, int);getService(Context, int, Intent, int);
从方法名就能明白,在Intent
被启动时,会启动Activity
,发送广播,启动服务。
所以如果我们想要实现点击RemoteViews
的某个按钮后来启动Activity
,代码就如下:
Intent intent = new Intent(this, MainActivity.class);PendingIntent pendingIntent = PendingIntent.getActivity(this, 21, intent, PendingIntent.FLAG_UPDATE_CURRENT);remoteViews.setOnClickPendingIntent(R.id.iv_add, pendingIntent);
那么回到我们之前的问题,怎么实现点击按钮来实现通知上数字的变化呢?
方法是控制点击按钮后发送一条广播,然后App监听这个广播,收到广播后再次发送相同id
的通知,新的通知是更改了数字了的。这就是具体的思路,下面是具体的代码实现。
发送通知的代码:
private void sendNotification() { RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.layout_number); Intent addIntent = new Intent(); addIntent.setAction("com.example.xujiafeng.notificationrefresh.add"); remoteViews.setOnClickPendingIntent(R.id.iv_add, PendingIntent.getBroadcast(MainActivity.this, 10, addIntent, PendingIntent.FLAG_UPDATE_CURRENT)); Intent minusIntent = new Intent(); addIntent.setAction("com.example.xujiafeng.notificationrefresh.minus"); remoteViews.setOnClickPendingIntent(R.id.iv_add, PendingIntent.getBroadcast(MainActivity.this, 10, minusIntent, PendingIntent.FLAG_UPDATE_CURRENT)); remoteViews.setTextViewText(R.id.tv_value, String.valueOf(value)); notification = new NotificationCompat.Builder(MainActivity.this) .setSmallIcon(R.mipmap.ic_launcher) .setContentTitle("ContentTitle") .setContentText("ContentText") .setWhen(System.currentTimeMillis()) .setTicker("Ticker") .setContent(remoteViews) .build(); mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); mNotificationManager.notify(12, notification); }
广播接收器:
public class NotificationReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); switch (action) { case "com.example.xujiafeng.notificationrefresh.add": value++; sendNotification(); break; case "com.example.xujiafeng.notificationrefresh.minus": value--; sendNotification(); break; } } }
注册广播:
IntentFilter filter = new IntentFilter(); filter.addAction(ADD_ACTION); filter.addAction(MINUS_ACTION); mReceiver = new NotificationReceiver(); registerReceiver(mReceiver, filter);
这样就完成了,运行效果如下:
项目的GitHub地址
更多相关文章
- MVC架构设计与经典三层模型
- 老罗Android开发视频教程_基于JavaSE开发(适合Android初学者菜鸟
- Android(安卓)常用控件接口监听
- 第3章 UI开发的点点滴滴
- android HandlerThread使用小例
- 主程序与widget
- android的ANR原理剖析及图解(基于android9.0)
- 写一个android小闹钟
- Android(安卓)机型适配之百分比适配 ConstraintLayout