RemoteViews一 仿qq音乐自定义通知栏实现快捷切换歌曲

RemoteViews一 仿qq音乐自定义通知栏实现快捷切换歌曲

定义:RemoteViews表示一种view结构,它可以在其他进程中显示,由于它在其它进程中,为了能够更新它的界面,RemoteViews提供了一组基础的操作用于更新它的界面。

本文大概需要5分钟,从以下三方面讲解。文章底部有总结,急性子可以直接看总结,快速掌握知识点。

  1. 一、成果展示
  2. 二、代码讲解
  3. 三、总结
一、成果展示

仿照qq音乐通知栏切换歌曲(缺图,只能以文字代替)

RemoteViews一 仿qq音乐自定义通知栏实现快捷切换歌曲

点击下一曲后,执行相应的代码(以相应Toast代替)

RemoteViews一 仿qq音乐自定义通知栏实现快捷切换歌曲

后台启动相应的service执行切换歌曲和暂停等逻辑

RemoteViews一 仿qq音乐自定义通知栏实现快捷切换歌曲

二、代码讲解

package android.com.remoteviews;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.RemoteViews;

import static android.R.string.no;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initRemoteViews();
    }

    private void initRemoteViews () {
        Notification notification = new Notification();
        notification.icon = R.mipmap.ic_launcher;
        notification.tickerText = "remoteviewTest";
        notification.when = System.currentTimeMillis();
        notification.flags = Notification.FLAG_AUTO_CANCEL;
        Intent intent = new Intent(this, SecondActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.layout_remoteviews);
        remoteViews.setTextViewText(R.id.tv_remote, "暧昧");
        remoteViews.setImageViewResource(R.id.iv_remote,R.mipmap.ic_launcher);
        Intent changeService = new Intent(this, ChangeService.class);
        changeService.putExtra("data","下一曲");
        PendingIntent changeIntent = PendingIntent.getService(this, 1, changeService, PendingIntent.FLAG_UPDATE_CURRENT);
        changeService.putExtra("data","暂停");
        PendingIntent pauseIntent = PendingIntent.getService(this, 2, changeService, PendingIntent.FLAG_UPDATE_CURRENT);

        remoteViews.setOnClickPendingIntent(R.id.tv_pause,pauseIntent);
        remoteViews.setOnClickPendingIntent(R.id.tv_next,changeIntent);
        PendingIntent clickIntent = PendingIntent.getActivity(this, 1, new Intent(this, ThirdActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
        remoteViews.setOnClickPendingIntent(R.id.iv_remote,clickIntent);
        notification.contentView = remoteViews;
        notification.contentIntent = pendingIntent;
        NotificationManager notifacationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notifacationManager.notify(2,notification);
    }
}

上面是核心代码,以下会分块讲解:首先需要notification,设置参数,icon应该是每一首歌曲对应的图片

Notification notification = new Notification();
        notification.icon = R.mipmap.ic_launcher;
        notification.tickerText = "remoteviewTest";
        notification.when = System.currentTimeMillis();
        notification.flags = Notification.FLAG_AUTO_CANCEL;

然后构造出PendingIntent

Intent intent = new Intent(this, SecondActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

再然后,构造出remoteviews,它有两个参数,一个是包名,另一个是布局的id,这里我写了一个简单的展示在通知栏的布局。注意了,remoteview设置文字和图片资源都没有findViewById,只能通过这种set方法,将对应的id和资源传进去。(这里先说用法,remoteview机制的原理在后面讲解)

RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.layout_remoteviews);
        remoteViews.setTextViewText(R.id.tv_remote, "暧昧");
        remoteViews.setImageViewResource(R.id.iv_remote,R.mipmap.ic_launcher);

布局的代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:gravity="center_vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/iv_remote"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher_round"/>
    <TextView
        android:id="@+id/tv_remote"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:text="i am a apple"/>


    <TextView
        android:id="@+id/tv_pause"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:text="暂停"/>
    <TextView
        android:id="@+id/tv_next"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:text="下一曲"/>

    <TextView
        android:id="@+id/tv_close"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:text="关闭"/>


</LinearLayout>

这里要澄清以下,不是非要用textview,而是我没有图,只能用文字代替,等以后又图了做个好看的哈哈。

下面说下remoteview上面点击事件,同理没有直接设置点击事件的方法(进它的源码瞅一眼就知道为啥了),还是只能传进去penddingIntent,由于qq音乐点击通知栏按钮直接切换歌曲,界面不发生变化所以,这块的penddingIntent用的PendingIntent.getService。当然,点击整个通知栏要跳到qq音乐主界面的话,就是底下PendingIntent.getActivity了。有一点,PendingIntent两个如果requescode一样,只是extras不一样会被认为是同一个peddingInetent。原因是,区分PenddingIntent是由内部intent和requescode,而内部intent区分是由componentName和intent-filter,ectras不参与Intent的匹配过程。如果notify方法的id是常量,那么不管PenddingIntent是否匹配,后面的通知会直接替换前面的通知。

Intent changeService = new Intent(this, ChangeService.class);
        changeService.putExtra("data","下一曲");
        PendingIntent changeIntent = PendingIntent.getService(this, 1, changeService, PendingIntent.FLAG_UPDATE_CURRENT);
        changeService.putExtra("data","暂停");
        PendingIntent pauseIntent = PendingIntent.getService(this, 2, changeService, PendingIntent.FLAG_UPDATE_CURRENT);

        remoteViews.setOnClickPendingIntent(R.id.tv_pause,pauseIntent);
        remoteViews.setOnClickPendingIntent(R.id.tv_next,changeIntent);
        PendingIntent clickIntent = PendingIntent.getActivity(this, 1, new Intent(this, ThirdActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
        remoteViews.setOnClickPendingIntent(R.id.iv_remote,clickIntent);

最后将自定义的remoteviews设置给notification的contentview并且获取系统NotificationManager,通过notifacationManager.notify方法将自定义的通知工具栏发出,展示在通知栏中国呢。

notification.contentView = remoteViews;
        notification.contentIntent = pendingIntent;
        NotificationManager notifacationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notifacationManager.notify(2,notification);

最后,本文只是仿照qq通知栏操作界面将remoteview的使用讲解一下,并不是一个播放器,再次强调,不是在做播放器。我这么想的,如果要做qq音乐的播放器通知更新,应该service里面去更新notinication的界面,比如,收到点击下一曲的penddingIntent,service去播放下一首歌曲,同时更新remoteview的界面(歌曲名字和歌曲对应的图片)对于qq音乐的其他操作,比如点击通知栏进入qq音乐主界面,就是notification的pendingIntent,它是由PenddingIntent.getActivity获取的。其他与qq音乐相关的先不管了,本文只提与remoteview有关的东西。

三、总结

  1. RemoteViews构造方法接受一个包名,一个layout的id;
  2. RemoteViews设置图片资源和文字资源接受id和资源;
  3. 没有直接方法设置点击事件,只能通过PenddingIntent相关方法实现;
  4. 将RemoteViews设置在notification中,通过NotificationManager的notify方法实现。
  5. 注意点:notify方法的id,penddingIntent的requestCode能用来区分PenddingIntent是不是同一个。

后记,RemoteViews还有一个最重要的使用就是桌面小部件(AppWidgetProvider),下一篇会写一个类似天气的桌面部件,并完成RemoteViews的原理讲解。

我的csdn博客欢迎关注我的微信公众号:

RemoteViews一 仿qq音乐自定义通知栏实现快捷切换歌曲

相关推荐