Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 多媒體控制 監聽事件-MediaSession-MediaStyle

Android 多媒體控制 監聽事件-MediaSession-MediaStyle

編輯:關於Android編程

這個系列僅僅包含控制部分 , 不包含音頻操作代碼 , 如 pauseAudio(); 我不會說這個方法裡是怎麼操作的 , 大家需要結合自己的音頻播放處理來實現.

Android多媒體控制

一個完整的多媒體播放器應該有的基礎功能:

通過耳機按鈕來控制歌曲 播放/暫停 上/下一首歌曲 當有線耳機/藍牙耳機 斷開連接和重新連接的時候 我們應該對應做出 暫停音頻 恢復音頻 使用系統提供的Notification.MediaStyle來控制歌曲 , 可以順利兼容 android 4.x ~ android 7.x 現在的系統樣式

> [[廣告]] https://github.com/ocwvar/DarkPurple > > 需要代碼樣例的同學可以在我的這個項目中查看 這個項目是個完整的音頻播放器 這裡的代碼均是從裡面提取 , 同時還有均衡器調節 頻譜動畫顯示等.. 目前正在不斷完善中 , 但由於上班 , 代碼更新可能不及時.

 

 

 

###1. 創建 MediaSessionCompat 對象
MediaSessionCompat sessionCompat = new MediaSessionCompat();

在這個構造方法中 , 我們使用這個:

MediaSessionCompat(Context context, String tag, ComponentName mbrComponent, PendingIntent mbrIntent)

//第一個參數 context: 這個沒有什麼好講的,大家都懂的
//第二個參數 tag: 這個是用於調試用的,隨便填寫即可
//第三個參數 mbrComponent: 這個是用於API21以下的時候傳遞耳機按鈕事件用的MediaSessionCompat.
//第四個參數 mbrIntent: 這個是給API21以下傳遞的時候攜帶的,一般設為 NULL即可

//例如:
//其中的HeadsetButtonReceiver是我們的API21以下實用的監聽器 , 我們稍候再講
ComponentName cn = new ComponentName(this.context.getApplicationContext().getPackageName(),
          HeadsetButtonReceiver.class.getName())
sessionCompat = new MediaSessionCompat(this.context.getApplicationContext(), "test", cn, null);

參數設置

sessionCompat = new MediaSessionCompat(...);

//設置MediaSession回調監聽,主要用於設置API21+的耳機按鈕監聽
sessionCompat.setCallback(new MediaSessionCallback());

//設置FLAG,FLAG的用途一看名字就知道了
sessionCompat.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS);

//設置MediaSession啟動 (很重要,不啟動則無法接受到數據)
sessionCompat.setActive(true);

 

 

 

 

2. 耳機多媒體按鈕監聽

API 21+ 的方式 MediaSessionCompat.Callback

//創建完成後用MediaSessionCompat.setCallback設置上即可使用

private class MediaSessionCallback extends MediaSessionCompat.Callback {

        @Override
        public boolean onMediaButtonEvent(Intent mediaButtonEvent) {

            //接收到監聽事件

        }

    }

API21- 的方式 HeadsetButtonReceiver

//在代碼中創建一個單獨的類文件,而不能作為一個內部類

public class HeadsetButtonReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        //接收到監聽事件

    }

}

//然後在注冊文件中注冊這個接收器


    
        
    


//最後在創建MediaSessionCompat對象的時候使用即可

 

 

 

 

3. Notification.MediaStyle 的創建

MediaStyle是什麼樣子的Notification呢?

在**Android 4.x**的是這樣的 ![這裡寫圖片描述](http://img.blog.csdn.net/20161107152026146)

在**Android 5.x ~ 6.x** 的是這樣的 ![這裡寫圖片描述](http://img.blog.csdn.net/20161107152048581)

在**Android 7.0** 的是這樣的 ![這裡寫圖片描述](http://img.blog.csdn.net/20161107152312833) MediaStyle使用的都是系統資源 , 除了布局之外 , 可以自定義的有: > 封面圖片 標題 副標題 按鈕樣式 背景顏色 使用MediaStyle的優點是不用擔心因系統變化而導致布局的變化 , 以及可以使用MediaSession作為我們的控制中介 , 雖然這部分不能自定義但個人認為還是挺值得的 .

對應的一個還有一個是Style是 **DecoratedMediaCustomViewStyle** 這個是可以提供部分自定義 , 但是修改部分僅是標題文字那部分的布局而已 , 並沒有什麼太大的作用 .

####**Notification.MediaStyle 創建代碼** PS:我們分開一段段講 ( 代碼太長了不好排版…. )

 

 

####**Part.1 基礎部分**
//創建 Notification 構建器
final NotificationCompat.Builder builder = new NotificationCompat.Builder(context);

//創建 MediaStyle 對象
final NotificationCompat.MediaStyle mediaStyle = new NotificationCompat.MediaStyle(builder);

    //在折疊的視圖中顯示的按鈕序號  根據下面設置的ACTION順序相關
    mediaStyle.setShowActionsInCompactView(0,1);

    //設置上面創建的MediaSession    
    mediaStyle.setMediaSession(sessionCompat.getSessionToken());

    //設置 MediaStyle 風格
    builder.setStyle(mediaStyle);

    //不顯示默認的通知開始時間
    builder.setShowWhen(false);

    //僅通知一次
    builder.setOnlyAlertOnce(true);

    //設置為當前正在運行狀態,不能清除
    builder.setOngoing(true);

    //設置點擊時不隱藏Notification
    builder.setAutoCancel(false);

    //設置狀態欄上面顯示的小圖標
    builder.setSmallIcon(R.drawable.ic_action_small_icon);

    //設置鎖屏是否顯示 在 Android5.0+ 的鎖屏界面可以隱藏Notification內容
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        builder.setVisibility(Notification.VISIBILITY_PUBLIC);
    }

    //設置通知優先度,讓我們的 Notification 顯示在最上面
    builder.setPriority(Notification.PRIORITY_MAX);

    //設置通知類別為服務
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        builder.setCategory(Notification.CATEGORY_SERVICE);
    }

    //點擊通知操作 使得用戶點擊Notification空白區域的時候打開指定的Activity
    Intent intent = new Intent(context, SelectMusicActivity.class);
    intent.setAction(Intent.ACTION_MAIN);
    intent.addCategory(Intent.CATEGORY_LAUNCHER);
    PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
    builder.setContentIntent(pendingIntent);

 

 

 

Part.2 創建和設置Action按鈕

    /**
     * 生成按鈕Action
     *
     * @param icon  圖標資源
     * @param intentAction  按鈕產生的廣播Action
     * @return 按鈕Action
     */
    private NotificationCompat.Action generateAction(int icon, String intentAction ) {
        return new NotificationCompat.Action( icon, intentAction, PendingIntent.getBroadcast(context, 0, new Intent(intentAction), PendingIntent.FLAG_CANCEL_CURRENT) );
    }

//根據播放狀態不同 , 設置不同主按鈕樣式 , 這裡的設置順序影響到折疊界面顯示的順序

//上一首 按鈕ACTION
builder.addAction(generateAction(android.R.drawable.ic_media_previous,MediaNotificationReceiver.BUTTON_PREV));
switch (audioStatus) {
    case Paused:
        //播放 按鈕ACTION
        builder.addAction(generateAction(android.R.drawable.ic_media_play,MediaNotificationReceiver.BUTTON_PLAY));
        break;
    case Playing:
        //暫停 按鈕ACTION
        builder.addAction(generateAction(android.R.drawable.ic_media_pause,MediaNotificationReceiver.BUTTON_PAUSE));
        break;
    }
//下一首 按鈕ACTION
builder.addAction(generateAction(android.R.drawable.ic_media_next,MediaNotificationReceiver.BUTTON_NEXT));

 

 

####**Part.3 設置顯示歌曲信息**
//更新標題
builder.setContentTitle(songItem.getTitle());
//更新作者
builder.setContentText(songItem.getArtist());
//更新封面
builder.setLargeIcon( 歌曲封面的Bitmap對象 );

最後就 builder.build(); 得到最終的成品 Notification

 

 

 

4.監聽耳機插拔事件

我們需要在耳機拔出的時候 暫停音樂 在耳機重新插入的時候 恢復音樂

耳機插入廣播接收器

/**
* 耳機插入廣播接收器
*/
public class HeadsetPlugInReceiver extends BroadcastReceiver {

    final IntentFilter filter;

    public HeadsetPlugInReceiver() {
        filter = new IntentFilter();

        if (Build.VERSION.SDK_INT >= 21) {
            filter.addAction(AudioManager.ACTION_HEADSET_PLUG);
        } else {
            filter.addAction(Intent.ACTION_HEADSET_PLUG);
        }
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent != null && intent.hasExtra("state") && AppConfigs.isResumeAudioWhenPlugin) {

            //通過判斷 "state" 來知道狀態
            final boolean isPlugIn = intent.getExtras().getInt("state") == 1;

        }
    }

}

 

 

####耳機拔出/斷開連接 廣播接收器
/**
* 耳機拔出廣播接收器
*/
private class HeadsetReceiver extends BroadcastReceiver {

    final IntentFilter filter;
    final BluetoothAdapter bluetoothAdapter;

    public HeadsetReceiver() {
        filter = new IntentFilter();
        filter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY); //有線耳機拔出變化
        filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); //藍牙耳機連接變化

        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        if (isRunningForeground) {
            //當前是正在運行的時候才能通過媒體按鍵來操作音頻
            switch (intent.getAction()) {
                case BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED:
                    if (
                        bluetoothAdapter != null && 
                        BluetoothProfile.STATE_DISCONNECTED == bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEADSET) && 
                        core.getCurrectStatus() == AudioCore.AudioStatus.Playing
                        ) 
                    {
                        //藍牙耳機斷開連接 同時當前音樂正在播放 則將其暫停
                        pause();
                    }
                    break;
                case AudioManager.ACTION_AUDIO_BECOMING_NOISY:
                    if (core.getCurrectStatus() == AudioCore.AudioStatus.Playing) {
                        //有線耳機斷開連接 同時當前音樂正在播放 則將其暫停
                        pause();
                    }
                    break;
            }
        }
    }

}

最後用 registerReceiver() 來注冊廣播監聽器即可

 

 

 

 

5.監聽電話狀態

我們需要在有電話來的時候和撥通電話的時候 暫停音頻 , 在通話結束之後 恢復音頻

要使得能接受到通話狀態 , 我們需要注冊一個權限 android.permission.READ_PHONE_STATE 這個權限在Android 6.0+上是需要用戶授予的

電話狀態廣播接收器

/**
*電話狀態廣播接收器
*/
public class PhoneStatusReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        if (intent != null && intent.getExtras() != null){

            final String status = intent.getStringExtra(TelephonyManager.EXTRA_STATE);

            switch (status){
                // "IDLE" 則代表通話結束或振鈴結束
                case "IDLE":
                    resume();
                    break;
                //其他狀態包括了撥通電話和新來電振鈴
                default:
                    pause();
                    break;
            }
        }

    }

}

在代碼端寫完之後 , 我們還需要在注冊清單中注冊一下:


    
        
    

 

 

 

 

教程完畢!!

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved