最近做项目的时候,遇到一个需求:发送一个带加减按钮和一个数字的通知,点击按钮后,通知的数字相应的要改变。

听起来很简单,不就是给两个按钮添加点击事件就可以了吗。可是,通知并不属于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地址

更多相关文章

  1. MVC架构设计与经典三层模型
  2. 老罗Android开发视频教程_基于JavaSE开发(适合Android初学者菜鸟
  3. Android(安卓)常用控件接口监听
  4. 第3章 UI开发的点点滴滴
  5. android HandlerThread使用小例
  6. 主程序与widget
  7. android的ANR原理剖析及图解(基于android9.0)
  8. 写一个android小闹钟
  9. Android(安卓)机型适配之百分比适配 ConstraintLayout

随机推荐

  1. Ubuntu 及windows 环境下android(Launcher
  2. How to start a new process for Android
  3. Android Camera HAL浅析
  4. Android Neon 优化方式讲解
  5. android 对话框集合
  6. Android:从Eclipse到Android Studio迁移工
  7. Android AutoCompleteTextView示例教程
  8. android jni系列教程
  9. Android(安卓)6.0 Launcher3隐藏小部件与
  10. android 计算器(2)