Android Notification click button to change the content scheme

When I was working on a project recently, I encountered a requirement: send a notification with plus and minus buttons and a number. After clicking the button, the number of the notification should be changed accordingly.

Notification style

It sounds simple, isn't it enough to add click events to the two buttons? However, the notification does not belong to the App process, but the process maintained by the Android system. The custom layout in the notification should RemoteViewsbe implemented through :

RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.layout_number);
NotificationCompat.Builder.setContent(remoteViews);

RemoteViewsIt is used to handle the layout scheme of cross-process display, generally used for notifications and desktop widgets. Due to different processes, RemoteViewsthe applied layout cannot be directly used findViewById()to find the control. It encapsulates some methods to update UI, for example:

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);

For more methods, please refer to the official API document.
It does not provide a method to directly add a click event to the control. So I encountered a dilemma.

So, can we directly write the layout of the entire notification as a custom control, and realize the click of the button in the custom control? Unfortunately, it is not possible. When sending a notification, the following error will be reported directly:

android.app.RemoteServiceException: Bad notification posted from package 
com.example.xujiafeng.notificationrefresh

In fact, it is normal to think about it carefully. If you can set the click event in such a simple way, RemoteViewsit is impossible for us to set the click event method for the control without exposing it to us.

So what else is there?

RemoteViewsAlthough there is no method to directly set the click event for the control, the following methods are provided:

void setOnClickPendingIntent (int viewId, PendingIntent pendingIntent)

Official documents explanation of this method are: the equivalent of calling
setOnClickListener(android.view.View.OnClickListener)to start the offer PendingIntent.

And PendingIntentis a delay Intent, it contains an internal Intent, when certain conditions are met he will not start Intent, it has four ways to get the object:

getActivity(Context, int, Intent, int);
getActivities(Context, int, Intent[], int);
getBroadcast(Context, int, Intent, int);
getService(Context, int, Intent, int);

It can be understood from the method name that when it Intentis started, it will start Activity, send a broadcast, and start the service.

So if we want to implement a click RemoteViewson a button to start later Activity, the code is as follows:

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);

So back to our previous question, how to realize the change of the number on the notification by clicking the button?

The method is to control the button to send a broadcast, and then the App monitors the broadcast, and sends the same idnotification again after receiving the broadcast . The new notification changes the number. This is the specific idea. The following is the specific code implementation.

Code to send notification:

    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);

    }

Broadcast receiver:

    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;
            }
        }
    }

Register to broadcast:

        IntentFilter filter = new IntentFilter();
        filter.addAction(ADD_ACTION);
        filter.addAction(MINUS_ACTION);
        mReceiver = new NotificationReceiver();
        registerReceiver(mReceiver, filter);

This is done, the running effect is as follows:
running result

The project's GitHub address

Published 19 original articles · praised 8 · visits 4041

Guess you like

Origin blog.csdn.net/u014068277/article/details/77933698