MediaButtonReceiver---独特的媒体广播接收器

本文介绍了如何使用MediaButtonReceiver实现耳机按键事件监听,并解释了为何通过AudioManager注册能使其成为唯一接收器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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里面注册:
     <receiver android:name=".MusicIntentReceiver" >
            <intent-filter>
                <action android:name="android.intent.action.MEDIA_BUTTON" />
            </intent-filter>
        </receiver>
广播接收类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的唯一接收器呢?

关于这个问题,博主自己看了下源码,也看了下网上一些牛人写的解析。  发现已经有人写的相当详细了。

这里贴一下地址:跟随源码,步步解析,MediaButtonReceiver如何成为MEDIA_BUTTON的唯一接收器

package com.vehicle.cloud.base.utils.media_session; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Bitmap; import android.support.v4.media.MediaMetadataCompat; import android.support.v4.media.session.MediaSessionCompat; import android.support.v4.media.session.PlaybackStateCompat; import com.vehicle.cloud.network.viewmodel.CloudSDKViewModel; public class MediaSessionUtils { private MediaSessionCompat mediaSession; private static MediaSessionUtils mediaSessionUtils; private Context context; private MediaButtonReceiver mediaButtonReceiver; // 添加媒体按钮接收器 public static MediaSessionUtils getInstance(){ if(mediaSessionUtils == null){ synchronized (MediaSessionUtils.class){ mediaSessionUtils = new MediaSessionUtils(); } } return mediaSessionUtils; } public void setContext(Context context){ this.context = context; } public void init(CloudSDKViewModel cloudSDKViewModel){ mediaSession = new MediaSessionCompat(context, "VehicleCloud"); mediaSession.setFlags( MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS ); mediaSession.setCallback(new MediaSessionCompat.Callback() { @Override public void onPlay() { super.onPlay(); cloudSDKViewModel.playOrPause(); updatePlaybackState(true); } @Override public void onPause() { super.onPause(); // mediaPlayer.pause(); cloudSDKViewModel.playOrPause(); updatePlaybackState(false); } @Override public void onSkipToNext() { super.onSkipToNext(); cloudSDKViewModel.playNextAudio(); updatePlaybackState(true); } @Override public void onSkipToPrevious() { super.onSkipToPrevious(); cloudSDKViewModel.playPreviousAudio(); updatePlaybackState(true); } @Override public void onSeekTo(long pos) { super.onSeekTo(pos); //TODO 调用代码拖动 // updatePlaybackState(mediaPlayer.isPlaying()); } }); // 注册媒体按钮广播接收器 registerMediaButtonReceiver(); mediaSession.setActive(true); } private void registerMediaButtonReceiver() { if (context != null && mediaSession != null) { mediaButtonReceiver = new MediaButtonReceiver(mediaSession); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_MEDIA_BUTTON); context.registerReceiver(mediaButtonReceiver, filter); } } private void updatePlaybackState(boolean isPlaying) { // long position = mediaPlayer.getCurrentPosition(); // long duration = mediaPlayer.getDuration(); PlaybackStateCompat state = new PlaybackStateCompat.Builder() .setActions( PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE | PlaybackStateCompat.ACTION_SKIP_TO_NEXT | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS | PlaybackStateCompat.ACTION_SEEK_TO | PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_STOP ) // .setState( // isPlaying ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED, // position, // isPlaying ? 1.0f : 0.0f, // SystemClock.elapsedRealtime() // ) .build(); mediaSession.setPlaybackState(state); } private void updateMetadata(String title, String artist, Bitmap albumArt, long duration) { MediaMetadataCompat metadata = new MediaMetadataCompat.Builder() .putString(MediaMetadataCompat.METADATA_KEY_TITLE, title) .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, artist) .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, albumArt) .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, duration) .build(); mediaSession.setMetadata(metadata); } public void release(){ // 注销广播接收器 if (mediaButtonReceiver != null && context != null) { try { context.unregisterReceiver(mediaButtonReceiver); } catch (IllegalArgumentException e) { // 接收器未注册或已注销 } mediaButtonReceiver = null; } if (mediaSession != null) { mediaSession.release(); } } } 监听不到方控的音乐事件
07-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值