RemoteViews 整理

Posted aoximin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RemoteViews 整理相关的知识,希望对你有一定的参考价值。

前言

RemoteViews表面意思就是远程的view,这个就很难理解了,远程的view。但是英语是抽象,remote本身就是偏僻的,偏远的意思。
所以remoteViews 就是地方view,天高皇帝远,要管理地方的view就需要下达圣旨了。
用途:一般就是通知栏与桌面小部件。
通知栏好理解,微信通知经常见到。
桌面小部件,这个无论是苹果还是按照,都有这个东西。
技术图片
这些就是系统自带的,然后我们也可以自己开发,但是这东西用的并不多,也有特定的app专门做这个,可以把桌面定制的吊炸天。

正文

如果说起这个remoteView,就必须提到一个巡按,这个巡按的名字就叫做pendingIntent。古时候,有些君主会留一个巡按在某一个地方,如果发生了一些大事,就要禀报一下。
remoteView 天高皇帝远,皇帝就要派一个自己人去体察民情,反馈和禀报。因为无法通过findViewById去直接控制地方,所以呢,当remoteView去上任的时候呢,一般都会带上pendingIntent。
pendingIntent 走的时候呢,一般要带上一个intent。比如皇帝派下去一个pendingIntent 和 remoteView 去上任,remoteView 年轻力壮,怕自己不在了,所以走得时候下了一封密旨给pendingIntent。
当用户点击的时候,pendingIntent就带上intent发给中央,留下老皇帝触发用户点击通知栏事件后续要做的事情,大概就是这么一个理。

notification

remoteView 其中一个应用就是通知栏。在通知栏的api(android 不同版本有不同的api,比如说android4.4的api就是19)中,因为api的变换,导致了需要根据不同版本去书写不同的code,美其名曰:兼容。

简单的通知就是这样:

public void createNotify(View view) {
    Intent resultIntent = new Intent(this, MainActivity.class);
    TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
    stackBuilder.addParentStack(MainActivity.class);
    stackBuilder.addNextIntent(resultIntent);
    PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
    NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
        /*
     使用Builder构造器来创建Notification对象
    */
    Notification notification = new NotificationCompat.Builder(this, "defult")
            //指定通知的标题内容
            .setContentTitle("Hello Word")
            //设置通知的内容
            .setContentText("This is just text")
            //指定通知被创建的时间
            .setWhen(System.currentTimeMillis())
            //设置通知的小图标
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            //设置通知的大图标
            .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_background))
            //添加点击跳转通知跳转
            .setContentIntent(resultPendingIntent)
            //实现点击跳转后关闭通知
            .setAutoCancel(true)
            .build();
            //id 固定只能是通知到这个通知块,可更新
            notificationManager.notify(1, notification);
}

效果:
技术图片
然后定制是这样的:
我们需要制定界面:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    >
    <ImageView
        android:layout_width="80dp"
        android:layout_height="match_parent"
        android:id="@+id/icon"
        android:src="@color/colorPrimary"
        />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        >
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="title"
            android:textSize="20dp"
            android:id="@+id/title"
            android:layout_marginLeft="20dp"
            android:gravity="center|left"
            />
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="content"
            android:textSize="18dp"
            android:id="@+id/content"
            android:layout_marginLeft="40dp"
            android:gravity="center|left"
            />
    </LinearLayout>
</LinearLayout>

然后通过remoteViews 来建立他们之间的沟通。
其实简单来说,我们的通知消息就是一个app,通过remoteViews 实现了我们app和通知栏app之间的沟通。
下面是实现code:

public void createCustomNotify(View view) {
    Intent resultIntent = new Intent(this, MainActivity.class);
    TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
    stackBuilder.addParentStack(MainActivity.class);
    stackBuilder.addNextIntent(resultIntent);
    PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);

    NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
   /*
     使用Builder构造器来创建Notification对象
    */
    RemoteViews remoteView =new RemoteViews(getPackageName(),R.layout.notification_layout);
    remoteView.setImageViewResource(R.id.icon,R.drawable.ic_launcher_foreground);
    remoteView.setTextViewText(R.id.title,"标题");
    remoteView.setTextViewText(R.id.content,"内容");
    Notification notification = new NotificationCompat.Builder(this, "defult")
            .setContent(remoteView)
            //指定通知被创建的时间
            .setWhen(System.currentTimeMillis())
            //设置通知的小图标
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            //设置通知的大图标
            .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_background))
            //添加点击跳转通知跳转
            .setContentIntent(resultPendingIntent)
            .setShowWhen(true)
            //实现点击跳转后关闭通知
            .setAutoCancel(true)
            .build();

    //id 固定只能是通知到这个通知块,可更新
    notificationManager.notify(2, notification);
}

效果:
技术图片
非常不好看哈。
如果是这样的自定义,只是界面上的花哨,我们可以点击图片后然后执行一些东西这样才能体现定义。
remoteViews 比如说通知通过intent,然后会用startActivity 去执行intent,所以打开了。
然后同样自定义的同样可以通过intent,在这里,假如自定义layout上有多个的事件,单纯去startActivity效果就无法实现了。
但是如果我们能监听到这个intent那么很多问题就简单了。
创建广播监听:

public class myBroadcastReceiver extends BroadcastReceiver {
    public  static  final  String actionImage="imageCallback";
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (actionImage.equals(actionImage))
        {
            Toast.makeText(context,"do this",Toast.LENGTH_SHORT).show();
        }
    }
}

然后再去创建监听:

private void init()
{
    myBroadcastReceiver = new myBroadcastReceiver();
    IntentFilter intentFilter = new IntentFilter(myBroadcastReceiver.actionImage);
    registerReceiver(myBroadcastReceiver, intentFilter);
}

最后只有设置绑定,也就是说用户点击某些事件后。

    public void createCustomNotify(View view) {
        Intent resultIntent = new Intent(this, MainActivity.class);
        TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
        stackBuilder.addParentStack(MainActivity.class);
        stackBuilder.addNextIntent(resultIntent);
        PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
        NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
       /*
         使用Builder构造器来创建Notification对象
        */
        RemoteViews remoteView =new RemoteViews(getPackageName(),R.layout.notification_layout);
        remoteView.setImageViewResource(R.id.icon,R.drawable.ic_launcher_foreground);
        remoteView.setTextViewText(R.id.title,"标题");
        remoteView.setTextViewText(R.id.content,"内容");
        Intent imageIntent=new Intent(myBroadcastReceiver.actionImage);
        PendingIntent imagePintent=PendingIntent.getBroadcast(this,0,imageIntent,0);
        remoteView.setOnClickPendingIntent(R.id.icon,imagePintent);
        Notification notification = new NotificationCompat.Builder(this, "defult")
                .setContent(remoteView)
                //指定通知被创建的时间
                .setWhen(System.currentTimeMillis())
                //设置通知的小图标
                .setSmallIcon(R.drawable.ic_launcher_foreground)
                //设置通知的大图标
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_background))
                //添加点击跳转通知跳转
                .setContentIntent(resultPendingIntent)
                .setShowWhen(true)
                //实现点击跳转后关闭通知
                .setAutoCancel(true)
                .build();

        //id 固定只能是通知到这个通知块,可更新
        notificationManager.notify(2, notification);
    }

关键部分就是:

// 实例化一个intent
Intent imageIntent=new Intent(myBroadcastReceiver.actionImage);
// 绑定intent,并且以广播的形式执行
PendingIntent imagePintent=PendingIntent.getBroadcast(this,0,imageIntent,0);
// 在icon 点击的时候触发
remoteView.setOnClickPendingIntent(R.id.icon,imagePintent);

效果:
技术图片

总之就是这个套路了,但是到了android 8 套路就换了,多了一个notificationChannel。
notificationChannel 这个东西用来做啥的呢?
我理解是频道的意思,比如说通知,用户可以更好的管理,接收还是不接受通知。
这东西就是来管理通知的,以前通知过于分散,设置一个id就是一个通知,然后用户不想要要一个一个去取消,同样开发者也麻烦。

    @RequiresApi(api = Build.VERSION_CODES.O)
    public void createNotificationChannel(String id, String name, int importance, String desc, String groupId) {
        if (mNotificationManager.getNotificationChannel(id) != null) return;
        NotificationChannel notificationChannel = new NotificationChannel(id, name, importance);
        notificationChannel.enableLights(true);
        notificationChannel.enableVibration(true);
        notificationChannel.setLightColor(Color.RED);
        notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
        notificationChannel.setShowBadge(true);
        notificationChannel.setBypassDnd(true);
        notificationChannel.setVibrationPattern(new long[]{100, 200, 300, 400});
        notificationChannel.setDescription(desc);
        notificationChannel.setGroup(groupId);
//      notificationChannel.setSound();
        mNotificationManager.createNotificationChannel(notificationChannel);
    }

上述中关键部分就两个一个是创建:

NotificationChannel notificationChannel = new NotificationChannel(id, name, importance);
mNotificationManager.createNotificationChannel(notificationChannel);

然后加入进去。中间的基本都是设置了,比如设置分为一个组setGroup,给一些描述setDescription等,必须这个id 注册后才能用于通知中。

Notification notification = new NotificationCompat.Builder(this, "defult")

上面这个defult设置为上面注册的id就行。
然后还有一个关键点:

Notification notification = new NotificationCompat.Builder(this, "defult")

可以设置角标,这就非常好了。在android 我们看到很少有应用可以有角标,基本上看到的只有qq,微信这些霸主才可以。实际上android 系统本身并没有开发,到了8才开发,但是腾讯和这些手机商有一些XXX,所以能拿到手机应用的角标。
到了8后,就不需要了,google本身就支持了。

总结

RemoteViews 不是一种远程view,而是一种远程控制view的方式。

以上是关于RemoteViews 整理的主要内容,如果未能解决你的问题,请参考以下文章

VS2015 代码片段整理

小程序各种功能代码片段整理---持续更新

常用python日期日志获取内容循环的代码片段

每秒更新一次通知中的 RemoteViews

带有 RemoteViews 的 Android 自定义通知布局

在 AsyncTask 回调后更新基于集合的 Widget RemoteViews