Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android開發之Mediaplayer狀態轉換圖及音頻焦點

Android開發之Mediaplayer狀態轉換圖及音頻焦點

編輯:關於Android編程

前言

  之前博客裡已經將了MediaPlayer的簡單應用,如何使用MediaPlayer在Android應用中播放音頻。這篇博客在MediaPlayer使用的基礎上,講解一下MediaPlayer的一些高級功能的使用,以及它的狀態轉換。對MediaPlayer還不了解的朋友可以先看看之前那篇博客:Android--MP3播放器MediaPlayer。

  本篇博客主要內容如下:

  1. MediaPlayer的狀態變換
  2. MediaPlayer的喚醒鎖
  3. MediaPlayer的音頻焦點

    MediaPlayer的狀態變換

      之前講到,使用MediaPlayer播放音頻,主要使用的是start()、pause()、stop()等方法操作MediaPlayer。但是除了開始、暫停、停止等,MediaPlayer還涉及到一些其他的狀態切換,有些狀態是可以雙向轉換的,有些只能單向環形轉換。如果在某狀態下,強行轉換狀態,會應發程序錯誤,例如在Preparing狀態下切換到Started狀態,是准備中強行開始播放,會出錯。下圖是官方文檔上的圖例,可以很清晰的表名MediaPlayer各個狀態的轉換情況。

    \

      上圖已經對MediaPlayer的各種狀態轉換有的清晰的介紹,這裡不再詳細講解了,只是提一下需要注意的地方:

    • Started(開始)/Paused(暫停)到StZ喎?/kf/ware/vc/" target="_blank" class="keylink">vcHBlZKOozaPWuaOpyse1pc/y16q7u6Oszt63qNTZtNNTdG9wcGVk1rG909equ7u1vVN0YXJ0ZWSjrNDo0qq+rcD6UHJlcGFyZWTW2NDC17DU2LLFv8nS1NbY0MKypbfFoaM8bGk+SW5pdGlhbGl6ZWSjqLP1yry7r6Op17TMrNDo0qrXsNTYyv2+3bLFv8nS1L340NBzdGFydCgpsqW3xaOstavKx8jnufvKudPDcHJlcGFyZUFzeW5jKCm3vbeo0uyyvde8sbijrNDo0qq1yLT917yxuM3qs8nU2b+qyryypbfFo6zV4sDv0OjSqsq508PSu7j2u9i197e9t6ijunNldE9uUHJlcGFyZWRMaXN0ZW5lcigpo6zL/Lvh1NrS7LK917DU2M3qs8m687X308OhozxsaT5FbmSjqL3hyvijqde0zKzKx9POwOvU2sbky/vXtMys1q7N4rXEo6zU2sjOus7XtMysvdS/ycfQu7ujrNK7sOPU2rK70OjSqrzM0PjKudPDTWVkaWFQbGF5ZXK1xMqxuvKjrLLFu+HKudPDcmVsZWFzZSgpu9jK1dfK1LShozxsaT5FcnJvcqOotO3O86Op17TMrMrH087A69TaxuTL+9e0zKzWrs3itcSjrNa709DU2k1lZGlhUGxheWVyt6LJ+rTtzvO1xMqxuvKyxbvh16q7u6GjzqrBy7Gjs9bTptPDtcTTw7unzOXR6aOs0ruw487Sw8e72LzgzP1zZXRPbkVycm9yTGlzdGVuZXIoKbvYtfe3vbeoo6zL/Lvh1NpNZWRpYVBsYXllcreiyfq07c7ztcTKsbrysbu72LX3oaMKPHA+CiA8L3A+CjxwPgo8c3Ryb25nPk1lZGlhUGxheWVytcS7vdDRy/g8L3N0cm9uZz48L3A+CjxwPgqhoaGh0ruw48q508NNZWRpYVBsYXllcrKlt8XS9Ma1wfejrM3GvPbKudPD0ru49lNlcnZpY2XAtLPQ1NhNZWRpYVBsYXllcqOstviyu8rH1rG909TaQWN0aXZpdHnA78q508Oho7WrysdBbmRyb2lkz7XNs7XEuaa6xMnovMbA76OszqrBy73a1Ly157PYz/u6xKOsyOe5+8nosbi0ptPay6/D39e0zKyjrM+1zbO9q8rUzby9tbXNu/LV37nYsdXSu9Cpw7vJ6LG4sdjQ67XEzNjQ1KOssPzAqENVULrNV2lmadOyvP6jrMi7uvOjrMjnufvKx9K7uPa688yosqW3xdL0wNa1xNOm08OjrL21tc1DVVC/ycTctbzWwtTauvPMqNTL0NC1xMqxuvK4ycjF0vTGtbXE1f2zo7Klt8WjrLnYsdVXaWZpvau/ycTctbzWws34wufS9Ma1wfe1xLvxyKGz9s/WtO3O86GjPC9wPgo8cD4KoaGhoc6qwcvIt7GjTWVkaWFQbGF5ZXK1xLPQ1Ni1xLf+zvHU2s+1zbPLr8PftcTKsbryvMzQ+NX9s6PUy9DQz8LIpaOsQW5kcm9pZM6qztLDx8zhuanBy9K71ta7vdDRy/god2FrZSBsb2Nrcym1xLv61saho8v8v8nS1NTaz7XNs8uvw9+1xKOs0sDIu7Gjs9bL+Lao07K8/rXE1f2zo7mk1/ehozwvcD4KPHA+CqGhoaHIt7Gj1NpNZWRpYVBsYXllctTL0NC1xMqxuvKjrMTExcLPtc2zy6/D38HLQ1VQ0rLE3NX9s6PUy9DQo6zQ6NKqyrnTw01lZGlhUGxheWVyLnNldFdha2VNb2RlKCnOqk1lZGlhUGxheWVyyei2qLu90NHL+KGjz8LD5srHc2V0V2FrTW9kZSgptcTHqcP7o7o8L3A+CjxwPgqhoTxlbT6hoaGhoaFzZXRXYWtlTW9kZShDb250ZXh0IGNvbnRleHQsIGludCBtb2RlKTwvZW0+PC9wPgo8cD4KoaGhobXa0ru49rLOyv3Kx7Wxx7DJz8/CzsSjrLXatv649rLOyv3OqtDo0qq808v4tcTXtMyso6yxu8notqjOqmludMDg0M21xLOjwb+jrLao0uXU2lBvd2VyTWFuYWdlctXiuPZmaW5hbMDg1tCho1Bvd2VyTWFuYWdlcsrH16jDxdPDwLS53MDtQW5kcm9pZLmmwsrP+7rEtcTL+Lao17TMrKOs0+vL+LaoQ1VQz+C52LXEo6zT0MvE1tajrLfWsfDJ6LaoQ1VQoaLGwcS7oaK8/MXMtci1xLj31taxo7PWu73Q0bXE17TMrKOs1NrV4sDv1rvQ6NKqyei2qM6qUEFSVElBTF9XQUtFX0xPQ0u8tL/JoaM8L3A+Cgo8cHJlIGNsYXNzPQ=="brush:java;">1 mediaPlayer = new MediaPlayer(); 2 // 設定CUP鎖定 3 mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);

        一般對於鎖而言,鎖定了通常需要解鎖,但是這裡的喚醒說與MediaPlayer關聯,所以只需要在使用完之後release()釋放MediaPlayer即可,無需顯式的為其解鎖。在使用setWakeMode設定喚醒鎖的時候,還必須為應用賦予相應的權限:

          

        

        再來說說如何鎖定wifi硬件在系統睡眠的時候保持正常運行。wifi鎖通過WifiLock進行操作,而WifiLock通過WifiManager進行管理,通過WifiManager.createWifiLock()進行Wifi鎖定。

          WifiManager.WifiLock createWifiLock(int lockType, String tag)

        這個方法有多個重載,這裡介紹的這個,第一個參數設定鎖的狀態,為一個int類型的常量,定義在Context類中,這裡的應用場景一般設定為WIFI_MODE_FULL即可。第二個參數為WifiLock的標志,用於確定wifiLock的。

      1         wifiLock= ((WifiManager) getSystemService(this.WIFI_SERVICE))
      2                 .createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock");
      3         wifiLock.acquire();

        當然,在應用中把Wifi鎖定之後,還需要在MediaPlayer.release()的時候為wifi硬件解鎖,為避免意外關閉的情況,最好在Android組件的onDestory()裡對其進行釋放,釋放Wifi鎖使用WifiLock.release()。  

      復制代碼
       1     /**
       2      * 停止播放
       3      */
       4     protected void stop() {
       5         if (mediaPlayer != null && mediaPlayer.isPlaying()) {
       6             mediaPlayer.stop();
       7             mediaPlayer.release();
       8             mediaPlayer = null;
       9             // 釋放wifi鎖
      10             wifiLock.acquire();
      11             btn_play.setEnabled(true);
      12             Toast.makeText(this, "停止播放", 0).show();
      13         }
      14 
      15     }
      16 
      17     @Override
      18     protected void onDestroy() {
      19         // 在activity結束的時候回收資源
      20         if (mediaPlayer != null && mediaPlayer.isPlaying()) {
      21             mediaPlayer.stop();
      22             mediaPlayer.release();
      23             mediaPlayer = null;
      24             // 釋放wifi鎖
      25             wifiLock.acquire();
      26         }
      27         super.onDestroy();
      28     }
      復制代碼

      MediaPlayer的音頻焦點

        眾所周知,Android是一個多任務的操作系統,所以對於音頻的播放,也許有幾個不同的媒體服務會同時播放,這樣可能導致一個比較雜亂的聲音環境,而錯過一些重要的聲音提醒。在Android2.2之後,Android提供了一種應用協商使用設備音頻輸出的機制,這種機制稱為音頻焦點。

        當應用程序需要輸出音頻或通知的時候,需要請求音頻焦點,當請求得到音頻焦點之後,監聽音頻焦點的變換,當音頻焦點變換了,根據返回回來的音頻焦點碼進行相應的處理。音頻焦點的注冊使用音頻管理器的AudioManager.requestAudioFocus()方法設定。它的簽名如下:

          int requestAudioFocus(AudioManager.OnAudioFocusChangeListener l, int streamType, int durationHint)

        這個方法的返回值是int類型,其含義被定義在AudioManager中以常量表示AUDIOFOCUS_REQUEST_FAILED(獲取音頻焦點成功)AUDIOFOCUS_REQUEST_GRANTED(獲取音頻焦點失敗)。其中重要的是第一個參數,為音頻焦點變化的回調函數,在其中可以設定如果音頻焦點變換了,當前應用如何管理MediaPlayer,第二個參數為媒體流的類型,第三個參數為持續的狀態。

        AudioManager.OnAudioFocusChangeListener為音頻焦點變換的監聽器,其中需要實現一個方法:onAudioFocusChange(int focusChange)在音頻焦點變換的時候回調。它有一個參數,為當前表示音頻焦點對於當前應用的狀態碼,通過這個狀態碼指定對應的操作,有些時候音頻狀態改變了,並不一定需要停止音頻的播放。

        focusChange有一下幾種狀態碼:

      • AUDIOFOCUS_GAIN:獲得音頻焦點。
      • AUDIOFOCUS_LOSS:失去音頻焦點,並且會持續很長時間。這是我們需要停止MediaPlayer的播放。
      • AUDIOFOCUS_LOSS_TRANSIENT:失去音頻焦點,但並不會持續很長時間,需要暫停MediaPlayer的播放,等待重新獲得音頻焦點。
      • AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:暫時失去音頻焦點,但是無需停止播放,只需降低聲音方法。 復制代碼
         1                 audioManager = (AudioManager) getSystemService(this.AUDIO_SERVICE);
         2                 int result = audioManager.requestAudioFocus(
         3                         new OnAudioFocusChangeListener() {
         4 
         5                             @Override
         6                             public void onAudioFocusChange(int focusChange) {
         7                                 switch (focusChange) {
         8                                 case AudioManager.AUDIOFOCUS_GAIN:
         9                                     // 獲得音頻焦點
        10                                     if (!mediaPlayer.isPlaying()) {
        11                                         mediaPlayer.start();
        12                                     }
        13                                     // 還原音量
        14                                     mediaPlayer.setVolume(1.0f, 1.0f);
        15                                     break;
        16 
        17                                 case AudioManager.AUDIOFOCUS_LOSS:
        18                                     // 長久的失去音頻焦點,釋放MediaPlayer
        19                                     if (mediaPlayer.isPlaying())
        20                                         mediaPlayer.stop();
        21                                     mediaPlayer.release();
        22                                     mediaPlayer = null;
        23                                     break;
        24 
        25                                 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
        26                                     // 展示失去音頻焦點,暫停播放等待重新獲得音頻焦點
        27                                     if (mediaPlayer.isPlaying())
        28                                         mediaPlayer.pause();
        29                                     break;
        30                                 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
        31                                     // 失去音頻焦點,無需停止播放,降低聲音即可
        32                                     if (mediaPlayer.isPlaying()) {
        33                                         mediaPlayer.setVolume(0.1f, 0.1f);
        34                                     }
        35                                     break;
        36                                 }
        37                             }
        38                         }, AudioManager.STREAM_MUSIC,
        39                         AudioManager.AUDIOFOCUS_GAIN);
        復制代碼

          

          源碼下載

        總結

          以上就講解了MediaPlayer的一些高級的內容,在掌握了MediaPlayer的使用之後,開發有關音樂播放類的應用的時候就可以得心應手了。從用戶體驗的方面出發,如果真實開發一款播放器類的軟件,需要監聽AUDIO_BECOMING_NOISY的廣播,它會在音頻輸出源從其他輸出源變換到設備揚聲器的時候發出此廣播,監聽廣播在音頻輸出源改變到設備揚聲器的時候,停止播放,這樣確保在耳機或額外的音頻輸出硬件與設備斷開連接的時候,不至於重新從揚聲器繼續輸出音頻播放。

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