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地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值