前台服务Service更新Notification进度条
在弄音乐播放的app的时候,我们时常需要用一个前台Service来播放音乐,同时管理和更新Notification,而且,Notification的点击事件需要用Broadcast来传递。
今天就手把手来看看如何在Service中管理Notification以及Broadcast!
首先,我们先来看看Notification的布局,
xml文件如下:
<?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="wrap_content"
android:padding="20dp"
android:orientation="vertical"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@drawable/bg_notification">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:id="@+id/notify_cover"
android:layout_width="70dp"
android:layout_height="70dp"
android:src="@mipmap/ic_launcher"
android:layout_gravity="center_horizontal" />
<LinearLayout
android:id="@+id/ll_songinfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginLeft="20dp"
android:layout_gravity="center_vertical">
<TextView
android:id="@+id/notify_song"
android:text="歌曲名"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/notify_singer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="歌手"/>
</LinearLayout>
</LinearLayout>
<ProgressBar
android:id="@+id/notify_progress_bar"
android:layout_width="match_parent"
android:layout_height="10px"
android:layout_below="@id/notify_cover"
android:layout_marginTop="10dp"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:max="100"
android:progress="50"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="10dp"
android:paddingLeft="40dp"
android:paddingRight="40dp"
android:gravity="center"
>
<Button
android:id="@+id/notify_last_song"
android:layout_width="40dp"
android:layout_height="match_parent"
android:background="@drawable/ic_icon_last_music"/>
<Button
android:id="@+id/notify_pause"
android:layout_width="40dp"
android:layout_height="match_parent"
android:layout_marginLeft="40dp"
android:layout_marginRight="40dp"
android:background="@drawable/ic_play_btn_pause"/>
<Button
android:id="@+id/notify_next_song"
android:layout_width="40dp"
android:layout_height="match_parent"
android:background="@drawable/ic_icon_next_music"/>
</LinearLayout>
</LinearLayout>
没什么好说的,重点也不是这个!!
再来看看我们接收Notification点击事件的BroadcastReceiver,是用kotlin写的
class NotificationBroadcast : BroadcastReceiver() {
companion object {
//稍后设置点击事件Intent的Action
val START_OR_PAUSE = "com.example.hp.MSCloudMusic.StartOrPause"
}
/**
* @param context The Context in which the receiver is running.
* @param intent The Intent being received.
*/
override fun onReceive(context: Context?, intent: Intent?) {
Log.e("Broadcast: ","receive broadcast!")
}
}
然后在PlayService的onCreate方法中
public class PlayService extends Service {
private NotificationHelper notificationHelper;
Notification notification;
@Override
public void onCreate() {
super.onCreate();
//注册广播接收者
registerReceiver();
//设置Notification
setNotification();
}
/**
* 注册广播接受者
*/
private void registerReceiver() {
NotificationBroadcast broadcast = new NotificationBroadcast();
//动态设置该广播接收者接收的Action
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(NotificationBroadcast.Companion.getSTART_OR_PAUSE());
registerReceiver(broadcast,intentFilter);
}
/**
* 开启Notification
*/
private void setNotification(){
//初始化NotificationHelper
notificationHelper = new NotificationHelper(this);
//这里获取内容,等下设置到Notification上
String song="",singer="";
int progress=0;
if(mPlayingMusic!=null){
song = mPlayingMusic.getTitle();
singer = mPlayingMusic.getAlbumPic();
progress = (int)(((float)mPlayer.getCurrentPosition() / (float)mPlayer.getDuration())*100);
}
//通过NotificationHelper类来得到Notification
notification = notificationHelper.getPlayMusicNotification(song,singer,progress);
//开启前台服务
startForeground(1,notification);
}
}
Service主要注册了广播接受者和其接收的Action;然后通过NotificationHelper类的getPlayMusicNotification方法来创建Notification,然后startForeground来开启Notification,这里startForeground的第一个参数需要和后面更新Notification时传入的id一样。我们来看一下NotificationHelper这个类
public class NotificationHelper {
private NotificationManager manager;
private Context context;
private RemoteViews remoteViews;
private NotificationCompat.Builder builder;
public NotificationHelper(Context context){
this.context = context;
init();
}
public void init(){
if(manager==null) {
manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
}
}
private NotificationCompat.Builder getNotificationBuilder(){
if(builder!=null){
return builder;
}
//targetSdk26及以上需要添加NotificationChannel
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
NotificationChannel channel = new NotificationChannel("channel_id","channel_name",NotificationManager.IMPORTANCE_LOW);
channel.setLockscreenVisibility(VISIBILITY_SECRET);
manager.createNotificationChannel(channel);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
//设置状态栏上的小图标,否则会报错
builder.setSmallIcon(R.drawable.ic_icon_quantum_statistical);
this.builder = builder;
return this.builder;
}
public Notification getPlayMusicNotification(String song ,String singer,int progress){
NotificationCompat.Builder builder = getNotificationBuilder();
//自定义Notificaiton的时候需要用到RemoteViews,传入布局文件
remoteViews = new RemoteViews(context.getPackageName(), R.layout.notification_play_music);
//设置控件内容
remoteViews.setTextViewText(R.id.notify_song, TextUtils.isEmpty(song)?"未知":song);
remoteViews.setTextViewText(R.id.notify_singer,TextUtils.isEmpty(singer)?"未知":singer);
remoteViews.setProgressBar(R.id.notify_progress_bar,100,progress,false);
//设置点击事件,Action为NotificationBroadcast的静态变量com.example.hp.MSCloudMusic.StartOrPause
Intent intent = new Intent(NotificationBroadcast.Companion.getSTART_OR_PAUSE());
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,0,intent,0);
remoteViews.setOnClickPendingIntent(R.id.notify_pause,pendingIntent);
//将remoteViews设置给builder,setCustomContentView是正常情况下的视图
//setCustomBigContentView是展开时的Notification
//这两个方法可以传入不同的remoteViews,但是点击事件和内容也要分别设置
builder.setCustomContentView(remoteViews);
builder.setCustomBigContentView(remoteViews);
return builder.build();
}
//更新Notification的方法
public void updateNotification(String song,String singer,int progress){
Notification newNotification = getPlayMusicNotification(song,singer,progress);
//这里notify方法的第一个参数要和startForeground的的id一样
manager.notify(1,newNotification);
}
}
这里需要注意几点:
①targetSdk26及以上需要适配NotificationChannel
②设置状态栏上的小图标,否则会报错
其他的地方注释写的很清楚了。
这样,Service调用startForeground的时候,Notification就可以显示了,一个是正常情况下的高度,一个是展开后的高度
接下来就是Notification的更新了
public class PlayService extends Service {
//更新Notification
private void updateNotification() {
if(notificationHelper==null){
setNotification();
} else {
String song = "", singer = "";
int progress = 0;
if (mPlayingMusic != null) {
song = mPlayingMusic.getTitle();
singer = mPlayingMusic.getArtist();
progress = (int)(((float)mPlayer.getCurrentPosition() / (float)mPlayer.getDuration())*100);
// Log.e(TAG, mPlayer.getCurrentPosition()+"/"+mPlayer.getDuration());
// Log.e(TAG, progress+"");
}
//调用updateNotification
notificationHelper.updateNotification(song, singer, progress);
}
}
}
这里没什么,只是调用了NotificationHelper的updateNotification方法,传入新的内容
public void updateNotification(String song,String singer,int progress){
Notification newNotification = getPlayMusicNotification(song,singer,progress);
manager.notify(1,newNotification);
}
这里很简单,通过getPlayMusicNotification获取设置了新内容的Notification,然后调用manager的notify方法,这里的id需要和前面startforeground传入的id一样。
至此,Notification的更新也结束了! 点击按钮时,也能通过BroadcastReceiver处理事件了!
喜欢点个赞~~