【问题标题】:Media Player controls in Notification通知中的媒体播放器控件
【发布时间】:2016-04-01 23:15:55
【问题描述】:

我已经编写了完整的音乐播放器来从网络上流式传输音乐,但我不知道如何将媒体播放器控件放入通知中以及何时锁定屏幕。

我正在关注this tutorial 在通知栏中显示控件,但仍未获得如何在我的程序中使用相同的功能,我已导入所需的类,例如:NotificationService.javaConstants.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);
    }

【问题讨论】:

标签: android notifications lockscreen android-music-player


【解决方案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 供您参考

          【讨论】:

            猜你喜欢
            • 2020-05-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-09-18
            • 1970-01-01
            • 2012-01-22
            • 1970-01-01
            相关资源
            最近更新 更多