通知中的媒体播放器控件
Posted
技术标签:
【中文标题】通知中的媒体播放器控件【英文标题】:Media Player controls in Notification 【发布时间】:2016-04-01 23:15:55 【问题描述】:我已经编写了完整的音乐播放器来从网络上流式传输音乐,但我不知道如何将媒体播放器控件放入通知中以及何时锁定屏幕。
我正在关注this tutorial 在通知栏中显示控件,但仍未获得如何在我的程序中使用相同的功能,我已导入所需的类,例如:NotificationService.java
和 Constants.java
。
这是我在通知栏中得到的:
[]
我很困惑。为什么我没有得到我正在播放的歌曲的标题,为什么暂停、上一个和下一个按钮不起作用等等...
NotificationService.java:
public class NotificationService extends Service
Notification status;
private final String LOG_TAG = "NotificationService";
@Override
public void onDestroy()
super.onDestroy();
@Override
public IBinder onBind(Intent intent)
return null;
@Override
public int onStartCommand(Intent intent, int flags, int startId)
if (intent.getAction().equals(Constants.ACTION.STARTFOREGROUND_ACTION))
showNotification();
Toast.makeText(this, "Service Started", Toast.LENGTH_SHORT).show();
else if (intent.getAction().equals(Constants.ACTION.PREV_ACTION))
Toast.makeText(this, "Clicked Previous", Toast.LENGTH_SHORT).show();
Log.i(LOG_TAG, "Clicked Previous");
else if (intent.getAction().equals(Constants.ACTION.PLAY_ACTION))
Toast.makeText(this, "Clicked Play", Toast.LENGTH_SHORT).show();
Log.i(LOG_TAG, "Clicked Play");
else if (intent.getAction().equals(Constants.ACTION.NEXT_ACTION))
Toast.makeText(this, "Clicked Next", Toast.LENGTH_SHORT).show();
Log.i(LOG_TAG, "Clicked Next");
else if (intent.getAction().equals(Constants.ACTION.STOPFOREGROUND_ACTION))
Log.i(LOG_TAG, "Received Stop Foreground Intent");
Toast.makeText(this, "Service Stoped", Toast.LENGTH_SHORT).show();
stopForeground(true);
stopSelf();
return START_STICKY;
private void showNotification()
// Using RemoteViews to bind custom layouts into Notification
RemoteViews views = new RemoteViews(getPackageName(), R.layout.status_bar);
RemoteViews bigViews = new RemoteViews(getPackageName(), R.layout.status_bar_expanded);
// showing default album image
views.setViewVisibility(R.id.status_bar_icon, View.VISIBLE);
views.setViewVisibility(R.id.status_bar_album_art, View.GONE);
bigViews.setImageViewBitmap(R.id.status_bar_album_art,
Constants.getDefaultAlbumArt(this));
Intent notificationIntent = new Intent(this, MusicPlayerActivity.class);
notificationIntent.setAction(Constants.ACTION.MAIN_ACTION);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Intent previousIntent = new Intent(this, NotificationService.class);
previousIntent.setAction(Constants.ACTION.PREV_ACTION);
PendingIntent ppreviousIntent = PendingIntent.getService(this, 0, previousIntent, 0);
Intent playIntent = new Intent(this, NotificationService.class);
playIntent.setAction(Constants.ACTION.PLAY_ACTION);
PendingIntent pplayIntent = PendingIntent.getService(this, 0, playIntent, 0);
Intent nextIntent = new Intent(this, NotificationService.class);
nextIntent.setAction(Constants.ACTION.NEXT_ACTION);
PendingIntent pnextIntent = PendingIntent.getService(this, 0, nextIntent, 0);
Intent closeIntent = new Intent(this, NotificationService.class);
closeIntent.setAction(Constants.ACTION.STOPFOREGROUND_ACTION);
PendingIntent pcloseIntent = PendingIntent.getService(this, 0, closeIntent, 0);
views.setOnClickPendingIntent(R.id.status_bar_play, pplayIntent);
bigViews.setOnClickPendingIntent(R.id.status_bar_play, pplayIntent);
views.setOnClickPendingIntent(R.id.status_bar_next, pnextIntent);
bigViews.setOnClickPendingIntent(R.id.status_bar_next, pnextIntent);
views.setOnClickPendingIntent(R.id.status_bar_prev, ppreviousIntent);
bigViews.setOnClickPendingIntent(R.id.status_bar_prev, ppreviousIntent);
views.setOnClickPendingIntent(R.id.status_bar_collapse, pcloseIntent);
bigViews.setOnClickPendingIntent(R.id.status_bar_collapse, pcloseIntent);
views.setImageViewResource(R.id.status_bar_play,
R.drawable.apollo_holo_dark_pause);
bigViews.setImageViewResource(R.id.status_bar_play,
R.drawable.apollo_holo_dark_pause);
views.setTextViewText(R.id.status_bar_track_name, "Song Title");
bigViews.setTextViewText(R.id.status_bar_track_name, "Song Title");
views.setTextViewText(R.id.status_bar_artist_name, "Artist Name");
bigViews.setTextViewText(R.id.status_bar_artist_name, "Artist Name");
bigViews.setTextViewText(R.id.status_bar_album_name, "Album Name");
status = new Notification.Builder(this).build();
status.contentView = views;
status.bigContentView = bigViews;
status.flags = Notification.FLAG_ONGOING_EVENT;
status.icon = R.drawable.ic_launcher;
status.contentIntent = pendingIntent;
startForeground(Constants.NOTIFICATION_ID.FOREGROUND_SERVICE, status);
Constants.java:
public class Constants
public interface ACTION
public static String MAIN_ACTION = "com.marothiatechs.customnotification.action.main";
public static String INIT_ACTION = "com.marothiatechs.customnotification.action.init";
public static String PREV_ACTION = "com.marothiatechs.customnotification.action.prev";
public static String PLAY_ACTION = "com.marothiatechs.customnotification.action.play";
public static String NEXT_ACTION = "com.marothiatechs.customnotification.action.next";
public static String STARTFOREGROUND_ACTION = "com.marothiatechs.customnotification.action.startforeground";
public static String STOPFOREGROUND_ACTION = "com.marothiatechs.customnotification.action.stopforeground";
public interface NOTIFICATION_ID
public static int FOREGROUND_SERVICE = 101;
public static Bitmap getDefaultAlbumArt(Context context)
Bitmap bm = null;
BitmapFactory.Options options = new BitmapFactory.Options();
try
bm = BitmapFactory.decodeResource(context.getResources(),
R.drawable.default_album_art, options);
catch (Error ee)
catch (Exception e)
return bm;
MusicPlayerActivity.java:
public class MusicPlayerActivity extends Activity
// ....
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_music_player);
mediaPlayer = new MediaPlayer();
audiosArrayList = new ArrayList<MusicPlayer>();
listview = (ListView) findViewById(R.id.list_slidermenu);
// ...
btnPlay.setOnClickListener(new OnClickListener()
@Override
public void onClick(View view)
try
play();
catch (Exception exception)
Log.v("exception:play", exception.toString());
);
btnPause.setOnClickListener(new OnClickListener()
@Override
public void onClick(View view)
try
pause();
catch (Exception exception)
Log.v("exception:pause", exception.toString());
);
btnNext.setOnClickListener(new OnClickListener()
@Override
public void onClick(View view)
try
next();
catch (Exception exception)
Log.v("exception:next", exception.toString());
);
btnPrev.setOnClickListener(new OnClickListener()
@Override
public void onClick(View view)
try
prev();
catch (Exception exception)
Log.v("exception:pause", exception.toString());
);
new JSONAsyncTask().execute("http://myurl/json/musics.json");
listview.setOnItemClickListener(new OnItemClickListener()
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id)
if (mediaPlayer != null && mediaPlayer.isPlaying())
try
mediaPlayer.stop();
catch (Exception e)
play();
);
......
// ...
public void startService(View v)
Intent serviceIntent = new Intent(MusicPlayerActivity.this, NotificationService.class);
serviceIntent.setAction(Constants.ACTION.STARTFOREGROUND_ACTION);
startService(serviceIntent);
【问题讨论】:
检查此代码github.com/googlesamples/android-UniversalMusicPlayer 【参考方案1】:尝试这样的事情(我使用整数作为操作):
intent.putExtra("action", ACTION_EXIT);
pendingIntent = PendingIntent.getService(this, intent.getIntExtra("action", 0), intent, PendingIntent.FLAG_UPDATE_CURRENT);
在公共静态 PendingIntent getService 中(上下文上下文,int requestCode,Intent 意图,int 标志) requestCode 必须是唯一的。
【讨论】:
【参考方案2】:您需要设置自定义意图操作,而不是 AudioPlayerBroadcastReceiver 组件类。
使用这样的自定义操作名称创建一个 Intent
Intent switchIntent = new Intent("com.example.app.ACTION_PLAY");
然后,注册 PendingIntent 广播接收器
PendingIntent pendingSwitchIntent = PendingIntent.getBroadcast(this, 100, switchIntent, 0);
然后,为播放控件设置一个 onClick,如果需要,对其他控件执行类似的自定义操作。
notificationView.setOnClickPendingIntent(R.id.btn_play_pause_in_notification, pendingSwitchIntent);
接下来,像这样在 AudioPlayerBroadcastReceiver 中注册自定义操作
<receiver android:name="com.example.app.AudioPlayerBroadcastReceiver" >
<intent-filter>
<action android:name="com.example.app.ACTION_PLAY" />
</intent-filter>
</receiver>
最后,当在 Notification RemoteViews 布局上点击播放时,您将收到 BroadcastReceiver 的播放动作
public class AudioPlayerBroadcastReceiver extends BroadcastReceiver
@Override
public void onReceive(Context context, Intent intent)
String action = intent.getAction();
if(action.equalsIgnoreCase("com.example.app.ACTION_PLAY"))
// do your stuff to play action;
编辑:如何为代码中注册的广播接收器设置意图过滤器
您还可以通过 Intent 过滤器从注册的广播接收器的代码中设置自定义操作,如下所示
// instance of custom broadcast receiver
CustomReceiver broadcastReceiver = new CustomReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
// set the custom action
intentFilter.addAction("com.example.app.ACTION_PLAY");
// register the receiver
registerReceiver(broadcastReceiver, intentFilter);
查看此链接了解更多信息
https://www.binpress.com/tutorial/using-android-media-style-notifications-with-media-session-controls/165
【讨论】:
【参考方案3】:您找到解决方案了吗?我可以用另一个代码向你解释。它有点相似,但我已经修改了它,因为我正在播放流音频。如果您需要帮助,请告诉我。
我只是想和你分享我的showNotification()
方法
private void showNotification()
if (intent.getAction().equals(Constants.ACTION.STARTFOREGROUND_ACTION))
//Start IntentNotification
Log.i(LOG_TAG, "Received Start Foreground Intent ");
Intent notificationIntent = new Intent(ForegroundService.this, MainActivity.class);
notificationIntent.setAction(Constants.ACTION.MAIN_ACTION);
//With this settings you can open the same Activity without recreate.
//But you have to put in your AndroidManifest.xml the next line: to your Activity
//activity android:name=".MainActivity" android:launchMode="singleInstance"
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
//Intent for Play
Intent playIntent = new Intent(this, ForegroundService.class);
playIntent.setAction(Constants.ACTION.PLAY_ACTION);
PendingIntent pplayIntent = PendingIntent.getService(this, 0, playIntent, 0);
//Intent for Pause
Intent pausaIntent = new Intent(this, ForegroundService.class);
pausaIntent.setAction(Constants.ACTION.PAUSE_ACTION);
PendingIntent pauseIntent = PendingIntent.getService(this, 0, pausaIntent, 0);
//Intent for Close
stopIntent = new Intent(this, ForegroundService.class);
stopIntent.setAction(Constants.ACTION.CLOSE_ACTION);
PendingIntent closeIntent = PendingIntent.getService(this, 0, stopIntent, 0);
//Icon for your notification
Bitmap icon = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
notifManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent pi = PendingIntent.getActivity(getApplicationContext(), 0,
new Intent(getApplicationContext(), MainActivity.class),
PendingIntent.FLAG_UPDATE_CURRENT);
// Build the notification object.
mNotificationBuilder = new Notification.Builder(this)
.setContentTitle("Thinking out Loud")
.setContentText("Ed Sheeran")
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(Bitmap.createScaledBitmap(icon, 128, 128, false))
.setContentIntent(pendingIntent)
.setOngoing(true)
.addAction(R.drawable.ic_play_service, "PLAY", pplayIntent) //you can set a specific icon
.addAction(R.drawable.ic_pause_service, "PAUSE", pauseIntent) //you can set a specific icon
.addAction(R.drawable.ic_close_service, "CLOSE", closeIntent);//you can set a specific icon
startForeground(Constants.NOTIFICATION_ID.FOREGROUND_SERVICE, mNotificationBuilder.build());
else if (intent.getAction().equals(Constants.ACTION.PLAY_ACTION))
Log.i(LOG_TAG, "Clicked Play");
//Click Play notification
else if (intent.getAction().equals(Constants.ACTION.PAUSE_ACTION))
Log.i(LOG_TAG, "Clicked PAUSE");
//This is for Pause
else if (intent.getAction().equals(Constants.ACTION.CLOSE_ACTION))
Log.i(LOG_TAG, "Clicked Close");
//This is for close the NotificationService
stopForeground(true);
else if (intent.getAction().equals(Constants.ACTION.STOPFOREGROUND_ACTION))
Log.i(LOG_TAG, "Received Stop Foreground Intent");
stopForeground(true);
//Stop Notification Service
stopSelf();
我的Constants.class
public class Constants
public interface ACTION
public static String MAIN_ACTION = "action.main";
public static String PREV_ACTION = "action.prev";
public static String PLAY_ACTION = "action.play";
public static String PAUSE_ACTION = "action.pause";
public static String NEXT_ACTION = "action.next";
public static String CLOSE_ACTION = "action.close";
public static String STARTFOREGROUND_ACTION = "action.startforeground";
public static String STOPFOREGROUND_ACTION = "action.stopforeground";
public interface NOTIFICATION_ID
public static int FOREGROUND_SERVICE = 101;
【讨论】:
【参考方案4】:你们所有的 PendingIntent 都有相同的 requestCode。这是其他通知操作不起作用的主要原因。
更改请求代码。
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
PendingIntent ppreviousIntent = PendingIntent.getService(this, 1, previousIntent, 0);
PendingIntent pplayIntent = PendingIntent.getService(this, 2, playIntent, 0);
PendingIntent pnextIntent = PendingIntent.getService(this, 3, nextIntent, 0);
PendingIntent pcloseIntent = PendingIntent.getService(this, 4, closeIntent, 0);
【讨论】:
【参考方案5】:要实现这一点,您需要如下媒体会话和通知构建器:
private void createMediaSession()
mediaSessionCompat = new MediaSessionCompat(this, "media session");
stateBuilder = new PlaybackStateCompat.Builder()
.setActions(
PlaybackStateCompat.ACTION_PLAY |
PlaybackStateCompat.ACTION_PAUSE |
PlaybackStateCompat.ACTION_PLAY_PAUSE |
PlaybackStateCompat.ACTION_SKIP_TO_NEXT |
PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
);
mediaSessionCompat.setMediaButtonReceiver(null);
mediaSessionCompat.setPlaybackState(stateBuilder.build());
mediaSessionCompat.setCallback(new MediaSessionCompat.Callback()
@Override
public void onPlay()
super.onPlay();
//write code to control your music
@Override
public void onPause()
super.onPause();
//write code to control your music
@Override
public void onSkipToNext()
super.onSkipToNext();
//write code to control your music
@Override
public void onSkipToPrevious()
super.onSkipToPrevious();
//write code to control your music
);
mediaSessionCompat.setActive(true);
private void showNotification()
notificationBuilder = new NotificationCompat.Builder(this, CHANNEL_ID);
NotificationCompat.Action playPauseAction = new NotificationCompat.Action(
icon, string,
MediaButtonReceiver.buildMediaButtonPendingIntent(this,
PlaybackStateCompat.ACTION_PLAY_PAUSE)
);
PendingIntent contentPendingIntent = PendingIntent.getActivity(this,
0, new Intent(this, MainActivity.class),0
);
notificationBuilder.setContentTitle("Song Title")
.setSmallIcon(R.mipmap.ic_launcher_round)
.setContentIntent(contentPendingIntent)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.addAction(playPauseAction)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setStyle(new androidx.media.app.NotificationCompat.MediaStyle()
.setMediaSession(mediaSessionCompat.getSessionToken())
.setShowActionsInCompactView(0));
notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(0, notificationBuilder.build());
最后你需要创建一个广播接收器,如下所示
public static class MyReceiver extends BroadcastReceiver
@Override
public void onReceive(Context context, Intent intent)
MediaButtonReceiver.handleIntent(mediaSessionCompat, intent);
你应该在 gradle 中添加以下依赖项
implementation 'androidx.media:media:1.1.0'
现在您已准备好在要显示通知的任何位置调用 showNotification() 方法。如果您仍有问题,可以查看this tutorial 供您参考
【讨论】:
以上是关于通知中的媒体播放器控件的主要内容,如果未能解决你的问题,请参考以下文章
如何在 android studio (java) 中清除通知