MediaButtonReceiver, 其实Android中并没有这个类的定义,它是由于自身的注册方式与实现功能被大家所俗称。前阵子要实现一个蓝牙耳机按键播放音乐的功能,有幸了解了一下。
MediaButtonReceiver ,顾名思义,就是用于接收多媒体按钮广播的,常用于耳机等多媒体设备的按键监听。
由于耳机设备上的按键点击都会发送广播,所以在一开始去实现耳机按键事件监听的时候,我用的是普通的BroadcastReceiver。
经过测试发现,在这种情况下点击音乐按键,手机会第一时间调用系统默认的音乐播放器。然后再次点击 就会在系统默认播放器执行相应操作(播放/暂停,上一首,下一首),
开始,我认为是我的广播优先级不够,然后在系统播放器接到广播后就关闭的其向下的传递,于是在注册的广播属性上添加android:priority="2147483647"(2147483647是int型最大值),然后再次测试。
结果在第一次点击耳机按键的时候,我自己的广播接收到这个按键的广播,与此同时,系统默认的音乐播放器也被调用,但是之后继续点击耳机按键,发现我自身的广播已经无法在接收广播了,系统默认播放器依然继续响应,推测系统默认器应该是在接收了按键广播之后,截断了其后续的传递。 于是我也尝试在自己第一次收到广播的同时,截断按键广播向下传递。 事实是- - 并没有什么luan用。 (原因不是很清楚,有知道的朋友麻烦在下方解惑,也可以QQ联系我。)
在这样的情况下,使用MediaButtonReceiver是很不错的选择。其实MediaButtonReceiver跟普通的广播最主要的差异之处,就是它需要通过AudioManager来注册。
下面是AudioManager类中注册MediaButtonReceiver的代码。
/**
* Register a component to be the sole receiver of MEDIA_BUTTON intents.
* @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
* that will receive the media button intent. This broadcast receiver must be declared
* in the application manifest. The package of the component must match that of
* the context you're registering from.
* @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
*/
@Deprecated
public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
if (eventReceiver == null) {
return;
}
if (!eventReceiver.getPackageName().equals(mContext.getPackageName())) {
Log.e(TAG, "registerMediaButtonEventReceiver() error: " +
"receiver and context package names don't match");
return;
}
// construct a PendingIntent for the media button and register it
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
// the associated intent will be handled by the component being registered
mediaButtonIntent.setComponent(eventReceiver);
PendingIntent pi = PendingIntent.getBroadcast(mContext,
0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
registerMediaButtonIntent(pi, eventReceiver);
}
1.注册一个唯一的针对MEDUA_BUTTON intents的广播接收器。
2.该接收器必须在manifest文件中注册。
3.该组件的包必须与你注册时的上下文匹配
4.推荐使用MediaSession的setMediaButtonReceiver(PendingIntent)来代替(好吧,这点不重要)
其实主要就是1 、2点需要注意,唯一的广播接收器,就是说在这个应用里只有这个广播接收器能接收MEDUA_BUTTON 的广播。
使用它的话,之前遇到的问题就迎刃而解了,
首先,注册:
代码里注册:
import android.app.Activity;
import android.content.ComponentName;
import android.media.AudioManager;
import android.os.Bundle;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((AudioManager)getSystemService(AUDIO_SERVICE)).registerMediaButtonEventReceiver(new ComponentName(this,MusicIntentReceiver.class));
}
}
manifest里面注册:
广播接收类MusicIntentReceiver.class:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.Toast;
public class MusicIntentReceiver extends BroadcastReceiver {
private static final String LOG_TAG = "MusicIntentReceiver";
private Context mContext;
@Override
public void onReceive(Context context, Intent intent) {
mContext = context;
if (intent.getAction().equals(Intent.ACTION_MEDIA_BUTTON)) {
Log.i(LOG_TAG, "ACTION_MEDIA_BUTTON!");
KeyEvent keyEvent = (KeyEvent) intent.getExtras().get(
Intent.EXTRA_KEY_EVENT);
switch (keyEvent.getKeyCode()) {
case KeyEvent.KEYCODE_HEADSETHOOK:
Toast.makeText(context, "hook",Toast.LENGTH_SHORT).show();
break;
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
Toast.makeText(context, "PLAY_PAUSE",Toast.LENGTH_SHORT).show();
break;
case KeyEvent.KEYCODE_MEDIA_PLAY:
Toast.makeText(context, "PLAY",Toast.LENGTH_SHORT).show();
Log.d(LOG_TAG, "KEYCODE_MEDIA_PLAY!");
break;
case KeyEvent.KEYCODE_MEDIA_PAUSE:
Toast.makeText(context, "PAUSE", Toast.LENGTH_SHORT).show();
Log.d(LOG_TAG, "KEYCODE_MEDIA_PAUSE!");
break;
case KeyEvent.KEYCODE_MEDIA_STOP:
Toast.makeText(context, "STOP",Toast.LENGTH_SHORT).show();
break;
case KeyEvent.KEYCODE_MEDIA_NEXT:
Toast.makeText(context, "NEXT",Toast.LENGTH_SHORT).show();
break;
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
Toast.makeText(context, "PREVIOUS",Toast.LENGTH_SHORT).show();
break;
}
}
}
}
ok,这样就实现了耳机按键事件的监听。
做到这里,可以看到,其实跟正常的广播接收器相比,MediaButtonEventReceiver的接收都是一样,只是在注册的时候,是通过AudioManger来注册的。
为什么通过AudioManager的registerMediaButtonEventReceiver方法注册,就能使之成为MEDIA_BUTTON的唯一接收器呢?
关于这个问题,博主自己看了下源码,也看了下网上一些牛人写的解析。 发现已经有人写的相当详细了。