0

У меня есть приложение для музыкального плеера с MusicPlayingService (расширение MediaBrowserServiceCompat) и виджет для управления сервисом. MusicPlayingService также ссылка на MusicStateManager (создать в MusicServices OnCreate), который реализует «MediaSessionCompat.Callback» и обрабатывает все обратные вызовы из текущего MediaSession: mSession.setCallback(MusicStateManager);PendingIntent от Widget потерян, когда служба остановлена ​​

public class MusicPlayingService extends MediaBrowserServiceCompat implements 
    AudioManager.OnAudioFocusChangeListener { 

@RequiresPermission(Manifest.permission.READ_PHONE_STATE) 
@Override 
public void onCreate() { 
    super.onCreate(); 
    Log.d(TAG, "MusicPlayingService started"); 

    ..... 

    mPlayerStateManager = new MusicStateManager(this); 

    ..... 
} 

@Override 
public int onStartCommand(Intent intent, int flags, int startId) { 
    Log.d(TAG, "onStartCommand"); 
    MediaButtonReceiver.handleIntent(mPlayerStateManager.getSession(), intent); 
    return START_STICKY; 
} 

My Widget тогда имеет кучу Pending намерений, которые посылаются к MusicPlayingService и обрабатывается MusicStateManager. Все отлично работает.

public class MusicStateManager extends MediaSessionCompat.Callback { 

.... 

public MusicStateManager(@NonNull MusicStateManager argService) { 
    Log.d(TAG, "setting service"); 
    mPlayerService = argService; 

    ComponentName mediaButtonReceiver = new ComponentName(mPlayerService, HeadsetReceiver.class); 
    mSession = new MediaSessionCompat(mPlayerService, SESSION_TAG, mediaButtonReceiver, null); 
    mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | 
      MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS); 

    Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); 
    PendingIntent pendingMediaButtonIntent = PendingIntent.getBroadcast(mPlayerService, 0, mediaButtonIntent, 0); 
    mSession.setMediaButtonReceiver(pendingMediaButtonIntent); 

    Intent toggleIntent = new Intent(NotificationPlayer.toggleAction); 
    PendingIntent pendingToggleIntent = PendingIntent.getBroadcast(mPlayerService, 0, toggleIntent, 0); 
    mSession.setMediaButtonReceiver(pendingToggleIntent); 

    mSession.setCallback(this); 
    mSession.setActive(true); 

} 

    /** 
    * Callback method called from MusicStateManager whenever the music is about to play. 
    */ 
    public void onPlay() { 
     Log.d(TAG, "onPlay"); 

     ....... 
    } 

    @Override 
    public void onCustomAction(String action, Bundle extras) { 
     Log.d(TAG, "received action: " + action); // NoI18N 

     if (ACTION_TOGGLE.equals(action)) { 
      mPlayerService.toggle(); 
     } 
    } 

Дело есть. Если я заблокирую приложение, музыкальный сервис отключится (очевидно). Если я затем нажму кнопку на моем виджете, он снова запустит мой сервис (я вижу это из различных Log.d (...) в LogCat. Однако PendingIntent из виджета теряется и никогда не обрабатывается.

Это странное значение для пользователя. В большинстве случаев кнопки в виджет будут работать (когда служба работает). Однако иногда (когда служба не работает) кнопки не будут ничего делать при первом нажатии, но если вы снова нажмете их они будут работать (потому что первая пресса начала службы, но не смог справиться с намерением.

Любая идея, как я могу отладить эту проблему и посмотреть, что происходит с моим PendingIntent?

+0

В вашем коде не указано, где вы настроили PendingIntents для своего виджета. Кроме того, вы вызываете 'setMediaButtonReceiver' несколько раз, что просто переопределяет ранее установленное значение и используется только для [перезапуска воспроизведения с медиа-кнопок] (https://developer.android.com/reference/android/support/v4/ media/session/MediaSessionCompat.html # setMediaButtonReceiver (android.app.PendingIntent)), который не будет вызываться или вообще не изменяет поведение вашего виджета. Можете ли вы включить код виджета и любые вызовы «BroadcastReceiver.onReceive()» или «Service.onStartCommand()»? – ianhanniballake

+0

Я просто добавляю все, что вы просили. Однако, когда я собирался скопировать/вставить мои PendingIntents, я заметил, что я использовал applicationContext в качестве контекста. Это оказалось проблемой! Причина, по которой мне было сложно отлаживать, было то, что когда приложение было запущено, оно также запустило MusicService, и из LogCat было похоже, что MusicService запускался правильно. –

+0

Хорошо, я до сих пор не уверен, что «PendingIntent» вы используете с помощью «RemoteViews» вашего виджета. Я ожидал, что код, который включает [setOnClickPendingIntent] (https://developer.android.com/reference/android/widget/RemoteViews .html # setOnClickPendingIntent (интермедиат,% 20android.app.PendingIntent)). – ianhanniballake

ответ

0

в лучший способ создать PendingIntent s для воспроизведения мультимедиа - MediaButtonReceiver.buildMediaButtonPendingIntent(). Это позволяет вам передать константу PlaybackStateCompat.ACTION_, которая вызовет правильный обратный вызов.

PendingIntent playPendingIntent = MediaButtonReceiver 
    .buildMediaButtonPendingIntent(context, PlaybackStateCompat.ACTION_PLAY); 

Кажется, у вас уже есть правильный MediaButtonReceiver.handleIntent() вызов onStartCommand(), но вы также должны убедиться, что при создании MediaSessionCompat, что вы включили правильные действия по телефону setPlaybackState():

// Ideally, you should keep a reference to this Builder to update it, 
// rather than create it from scratch each time 
PlaybackStateCompat.Builder playbackStateBuilder = new PlaybackStateCompat.Builder() 
    .setActions(PlaybackStateCompat.ACTION_PLAY | 
       PlaybackStateCompat.ACTION_PLAY_PAUSE); 
mSession.setPlaybackState(playbackStateBuilder.build()); 

Как MediaSessionCompat по по умолчанию не допускается использование медиа-кнопок. Убедившись, что вы поддерживаете ACTION_PLAY прямо из создания экземпляра, вы убедитесь, что самый первый MediaButtonReceiver.handleIntent() правильно называет ваш MediaSessionCompat.Callback.