我一直在尝试在服务的帮助下检测蓝牙耳机的媒体键事件,但应用程序因以下错误而崩溃:
java.lang.RuntimeException: Unable to bind to service pk.mohammadadnan.tunalapp.MediaPlaybackService@d710f85 with Intent { act=android.media.browse.MediaBrowserService cmp=pk.mohammadadnan.tunalapp/.MediaPlaybackService }: java.lang.NullPointerException: Attempt to invoke interface method 'android.os.IBinder androidx.media.MediaBrowserServiceCompat$MediaBrowserServiceImpl.onBind(android.content.Intent)' on a null object reference
我尝试将 MediaBrowserServiceCompat 更改为 MediaBrowserService,崩溃问题已解决,但未检测到媒体按钮。
MediaPlaybackService.class
public class MediaPlaybackService extends MediaBrowserServiceCompat {
//Not important for general audio service, required for class
@Nullable
@Override
public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, @Nullable Bundle rootHints) {
if(TextUtils.equals(clientPackageName, getPackageName())) {
return new BrowserRoot(getString(R.string.app_name), null);
}
return null;
}
@Override
public void onLoadChildren(@NonNull String parentId, @NonNull Result<List<MediaBrowserCompat.MediaItem>> result) {
result.sendResult(null);
}
private MediaSessionCompat mediaSessionCompat;
private MediaSessionCompat.Callback mediaSessionCompatCallBack = new MediaSessionCompat.Callback()
{
@Override
public void onPlay() {
super.onPlay();
Toast.makeText(getApplication(),"Play Button is pressed!",Toast.LENGTH_SHORT).show();
mediaSessionCompat.setActive(true);
setMediaPlaybackState(PlaybackStateCompat.STATE_PLAYING);
}
@Override
public void onPause() {
super.onPause();
Toast.makeText(getApplication(),"Pause Button is pressed!",Toast.LENGTH_SHORT).show();
setMediaPlaybackState(PlaybackStateCompat.STATE_PAUSED);
}
@Override
public void onSkipToNext() {
super.onSkipToNext();
Toast.makeText(getApplication(),"Next Button is pressed!",Toast.LENGTH_SHORT).show();
}
@Override
public void onSkipToPrevious() {
super.onSkipToPrevious();
Toast.makeText(getApplication(),"Previous Button is pressed!",Toast.LENGTH_SHORT).show();
}
@Override
public void onStop() {
super.onStop();
Toast.makeText(getApplication(),"Stop Button is pressed!",Toast.LENGTH_SHORT).show();
}
@Override
public boolean onMediaButtonEvent(Intent mediaButtonEvent) {
String intentAction = mediaButtonEvent.getAction();
if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction))
{
KeyEvent event = mediaButtonEvent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
if (event != null)
{
int action = event.getAction();
if (action == KeyEvent.ACTION_DOWN) {
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
// code for fast forward
return true;
case KeyEvent.KEYCODE_MEDIA_NEXT:
// code for next
return true;
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
// code for play/pause
Toast.makeText(getApplication(),"Play Button is pressed!",Toast.LENGTH_SHORT).show();
return true;
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
// code for previous
return true;
case KeyEvent.KEYCODE_MEDIA_REWIND:
// code for rewind
return true;
case KeyEvent.KEYCODE_MEDIA_STOP:
// code for stop
Toast.makeText(getApplication(),"Stop Button is pressed!",Toast.LENGTH_SHORT).show();
return true;
}
return false;
}
if (action == KeyEvent.ACTION_UP) {
}
}
}
return super.onMediaButtonEvent(mediaButtonEvent);
}
};
@Override
public void onCreate() {
Toast.makeText(this, "My Service Created", Toast.LENGTH_LONG).show();
Log.e("SERVICE", "onCreate");
initMediaSession();
mediaSessionCompat.setActive(true);
}
@Override
public void onDestroy() {
Toast.makeText(this, "My Service Stopped", Toast.LENGTH_LONG).show();
Log.e("SERVICE", "onDestroy");
mediaSessionCompat.release();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "My Service Started", Toast.LENGTH_LONG).show();
Log.e("SERVICE_STARTUP", "onStart");
Intent intentTop = new Intent(Intent.ACTION_MEDIA_BUTTON);
intentTop.setClass(this, MediaButtonReceiver.class);
PendingIntent mbrIntent = PendingIntent.getBroadcast(this,0,intent,0);
mediaSessionCompat.setMediaButtonReceiver(mbrIntent);
MediaButtonReceiver.handleIntent(mediaSessionCompat, intent);
return super.onStartCommand(intent, flags, startId);
}
private void initMediaSession() {
ComponentName mediaButtonReceiver = new ComponentName(getApplicationContext(), MediaButtonReceiver.class);
mediaSessionCompat = new MediaSessionCompat(getApplicationContext(), "Tag", mediaButtonReceiver, null);
mediaSessionCompat.setCallback(mediaSessionCompatCallBack);
mediaSessionCompat.setFlags( MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS );
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
mediaButtonIntent.setClass(this, MediaButtonReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, mediaButtonIntent, 0);
mediaSessionCompat.setMediaButtonReceiver(pendingIntent);
//setSessionToken(mediaSessionCompat.getSessionToken());
}
private void setMediaPlaybackState(int state) {
PlaybackStateCompat.Builder playbackstateBuilder = new PlaybackStateCompat.Builder();
if( state == PlaybackStateCompat.STATE_PLAYING ) {
playbackstateBuilder.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_PAUSE);
} else {
playbackstateBuilder.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_PLAY);
}
playbackstateBuilder.setState(state, PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN, 0);
mediaSessionCompat.setPlaybackState(playbackstateBuilder.build());
}
}
MainActivity.class
public class MainActivity extends AppCompatActivity {
private static final int STATE_PAUSED = 0;
private static final int STATE_PLAYING = 1;
private int mCurrentState;
private MediaBrowserCompat mMediaBrowserCompat;
private MediaControllerCompat mMediaControllerCompat;
private Button mPlayPauseToggleButton;
private MediaBrowserCompat.ConnectionCallback mMediaBrowserCompatConnectionCallback = new MediaBrowserCompat.ConnectionCallback() {
@Override
public void onConnected() {
super.onConnected();
try {
mMediaControllerCompat = new MediaControllerCompat(MainActivity.this, mMediaBrowserCompat.getSessionToken());
mMediaControllerCompat.registerCallback(mMediaControllerCompatCallback);
MediaControllerCompat.setMediaController(MainActivity.this,mMediaControllerCompat);
MediaControllerCompat.getMediaController(MainActivity.this).getTransportControls().playFromMediaId(String.valueOf(R.raw.warner_tautz_off_broadway), null);
} catch( RemoteException e ) {
}
}
};
private MediaControllerCompat.Callback mMediaControllerCompatCallback = new MediaControllerCompat.Callback() {
@Override
public void onPlaybackStateChanged(PlaybackStateCompat state) {
super.onPlaybackStateChanged(state);
if( state == null ) {
return;
}
switch( state.getState() ) {
case PlaybackStateCompat.STATE_PLAYING: {
mCurrentState = STATE_PLAYING;
break;
}
case PlaybackStateCompat.STATE_PAUSED: {
mCurrentState = STATE_PAUSED;
break;
}
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPlayPauseToggleButton = (Button) findViewById(R.id.button);
mMediaBrowserCompat = new MediaBrowserCompat(this, new ComponentName(this, MediaPlaybackService.class),
mMediaBrowserCompatConnectionCallback, getIntent().getExtras());
mMediaBrowserCompat.connect();
mPlayPauseToggleButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if( mCurrentState == STATE_PAUSED ) {
MediaControllerCompat.getMediaController(MainActivity.this).getTransportControls().play();
mCurrentState = STATE_PLAYING;
} else {
if( MediaControllerCompat.getMediaController(MainActivity.this).getPlaybackState().getState() == PlaybackStateCompat.STATE_PLAYING ) {
MediaControllerCompat.getMediaController(MainActivity.this).getTransportControls().pause();
}
mCurrentState = STATE_PAUSED;
}
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
if( MediaControllerCompat.getMediaController(MainActivity.this).getPlaybackState().getState() == PlaybackStateCompat.STATE_PLAYING ) {
MediaControllerCompat.getMediaController(MainActivity.this).getTransportControls().pause();
}
mMediaBrowserCompat.disconnect();
}
}
清单.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="pk.mohammadadnan.tunalapp">
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-feature android:name="android.hardware.bluetooth" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="androidx.media.session.MediaButtonReceiver" >
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
<action android:name="android.media.AUDIO_BECOMING_NOISY" />
</intent-filter>
</receiver>
<service android:name="pk.mohammadadnan.tunalapp.MediaPlaybackService"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
<action android:name="android.media.browse.MediaBrowserService" />
<action android:name="android.media.AUDIO_BECOMING_NOISY" />
</intent-filter>
</service>
</application>
</manifest>