Android中MediaButtonReceiver廣播監聽器的機制分析


 

                                                                                                                                轉載請注明出處:http://blog.csdn.net/qinjuning

 

 

            在Android中並沒有定義MediaButtonReceive這個廣播類,MediaButtonReceive只是作為一種通俗的命名方式來響應

   插入耳機后,點擊耳機上的按鈕(名稱:MEDIA_BUTTON)接受該廣播事件的類。所有該MEDIA_BUTTON的按下我們就簡稱

   為MEDIA_BUTTON廣播吧。

           

           顧名思義:它顯然是一個廣播接收器類(BroadbcastReceiver),那么它就具備了BroadbcastReceiver類的使用方式,

   但是,因為它需要通過AudioManager對象注冊,所以它有着自己的獨特之處(否則我也不會單獨拿出來分析,- -),后面我們

   會慢慢的講解。

 

        點擊MEDIA_BUTTON發送的Intent Action 為:

                        ACTION_MEDIA_BUTTON  ="android.intent.action.MEDIA_BUTTON"

 

        Intent 附加值為(Extra)點擊MEDIA_BUTTON的按鍵碼 :    

                        //獲得KeyEvent對象

                        KeyEvent keyEvent = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);

                        //獲得Action

                        String intentAction = intent.getAction() ;

 

AudioManager對象注冊MEDIA_BUTTON廣播的方法原型為:

 

   public voidregisterMediaButtonEventReceiver(ComponentNameeventReceiver)

          Register a component to be the sole receiverof MEDIA_BUTTON intents

          Parameters:                   

                eventReceiver  : identifier of a BroadcastReceiver that will receive the media button intent. This broadcast receiver

                                   must be declared in the application manifest.

 

   從注釋可知以下兩點:

      1、 在AudioManager對象注冊一個MediaoButtonRecevie,使它成為MEDIA_BUTTON的唯一接收器(這很重要,

          我們會放在后面講解)   也就是說只有我能收到,其他的都收不到這個廣播了,否則的話大家都收到會照成一定的混亂;

      2、   該廣播必須在AndroidManifest.xml文件中進行聲明,否則就監聽不到該MEDIA_BUTTON廣播了。

 

下面我們就簡單的寫一個MediaButtonReceiver類,並且在AndroidManifest.xml定義

 

1、  自定義的MediaButtonReceiver 廣播類

[java]  view plain copy print ?
  1. package com.qin.mediabutton;  
  2.   
  3. import android.content.BroadcastReceiver;  
  4. import android.content.Context;  
  5. import android.content.Intent;  
  6. import android.util.Log;  
  7. import android.view.KeyEvent;  
  8.   
  9. public class MediaButtonReceiver extends BroadcastReceiver {  
  10.     private static String TAG = "MediaButtonReceiver";  
  11.     @Override  
  12.     public void onReceive(Context context, Intent intent) {  
  13.         // 獲得Action  
  14.         String intentAction = intent.getAction();  
  15.         // 獲得KeyEvent對象  
  16.         KeyEvent keyEvent = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);  
  17.   
  18.         Log.i(TAG, "Action ---->" + intentAction + "  KeyEvent----->"+ keyEvent.toString());  
  19.   
  20.         if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) {  
  21.             // 獲得按鍵字節碼  
  22.             int keyCode = keyEvent.getKeyCode();  
  23.             // 按下 / 松開 按鈕  
  24.             int keyAction = keyEvent.getAction();  
  25.             // 獲得事件的時間  
  26.             long downtime = keyEvent.getEventTime();  
  27.   
  28.             // 獲取按鍵碼 keyCode  
  29.             StringBuilder sb = new StringBuilder();  
  30.             // 這些都是可能的按鍵碼 , 打印出來用戶按下的鍵  
  31.             if (KeyEvent.KEYCODE_MEDIA_NEXT == keyCode) {  
  32.                 sb.append("KEYCODE_MEDIA_NEXT");  
  33.             }  
  34.             // 說明:當我們按下MEDIA_BUTTON中間按鈕時,實際出發的是 KEYCODE_HEADSETHOOK 而不是  
  35.             // KEYCODE_MEDIA_PLAY_PAUSE  
  36.             if (KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE == keyCode) {  
  37.                 sb.append("KEYCODE_MEDIA_PLAY_PAUSE");  
  38.             }  
  39.             if (KeyEvent.KEYCODE_HEADSETHOOK == keyCode) {  
  40.                 sb.append("KEYCODE_HEADSETHOOK");  
  41.             }  
  42.             if (KeyEvent.KEYCODE_MEDIA_PREVIOUS == keyCode) {  
  43.                 sb.append("KEYCODE_MEDIA_PREVIOUS");  
  44.             }  
  45.             if (KeyEvent.KEYCODE_MEDIA_STOP == keyCode) {  
  46.                 sb.append("KEYCODE_MEDIA_STOP");  
  47.             }  
  48.             // 輸出點擊的按鍵碼  
  49.             Log.i(TAG, sb.toString());  
  50.         }  
  51.     }  
  52. }  

 

  2、  在AndroidManifest.xml聲明我們定義的廣播類。

 

[java]  view plain copy print ?
  1.  <receiver android:name="MediaButtonReceiver">  
  2.   <intent-filter >  
  3.         <action android:name="android.intent.action.MEDIA_BUTTON"></action>  
  4.   </intent-filter>  
  5. </receiver>  

 

         在模擬器上,我們可以手動構造MEDA_BUTTON的廣播,並且將它發送出去(后面會介紹)。

         如果有真機測試的話,按下MEDIA_BUTTON是可以接受到MEDIA_BUTTON廣播的,如果沒有接受到,請關閉所有應用

   程序,在觀察效果。

 

  繼續我們的下一步分析:

         前面我們說明通過registerMediaButtonEventReceiver(eventReceiver)方法注冊時使它成為MEDIA_BUTTON的

     唯一 接收器這個唯一是怎么實現的呢? 我們在源碼中,一步步追本溯源,相信一定可以找到答案,知道這“唯一“是

    怎么來的。

 

第一步、   為AudioManager注冊一個MediaButtonReceiver() ;

[java]  view plain copy print ?
  1. //獲得AudioManager對象  
  2. AudioManager mAudioManager =(AudioManager)getSystemService(Context.AUDIO_SERVICE);     
  3. //構造一個ComponentName,指向MediaoButtonReceiver類  
  4. //下面為了敘述方便,我直接使用ComponentName類來替代MediaoButtonReceiver類  
  5. ComponentName  mbCN = new ComponentName(getPackageName(),MediaButtonReceiver.class.getName());  
  6. //注冊一個MedioButtonReceiver廣播監聽  
  7. mAudioManager.registerMediaButtonEventReceiver(mbCN);  
  8. //取消注冊的方法  
  9. mAudioManager.unregisterMediaButtonEventReceiver(mbCN);  

         

        MediaButtonReceiver就是我們用來接收MEDIA_BUTTON的廣播類,下面為了敘述方便和直觀上得體驗,我直接使用

    ComponentName類來替代真正的MediaoButtonReceiver廣播類。

 

   說明 接下來分析的文件路徑全部在   frameworks/base/media/java/android/media/ 下

 

 第二步、 進入AudioManager.java進行查看 ,發現如下方法:

 

[java]  view plain copy print ?
  1. //注冊的方法為:  
  2. public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {  
  3.       //TODO enforce the rule about the receiver being declared in the manifest  
  4.       //我們繼續查看getService()方法,看看IAudioService類到底是什么?  
  5.        IAudioService service = getService();  
  6.       try {  
  7.         //只是簡單的調用了service的方法來完成注冊,繼續跟蹤  
  8.           service.registerMediaButtonEventReceiver(eventReceiver);  
  9.        
  10.       } catch (RemoteException e) {  
  11.           Log.e(TAG, "Dead object in registerMediaButtonEventReceiver"+e);  
  12.       }  
  13. }  
  14. //取消注冊的方法為  
  15. public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {  
  16.       IAudioService service = getService();    
  17.       try {  
  18.         //只是簡單的調用了service的方法來取消注冊,,繼續跟蹤  
  19.           service.unregisterMediaButtonEventReceiver(eventReceiver);  
  20.       } catch (RemoteException e) {  
  21.           Log.e(TAG, "Dead object in unregisterMediaButtonEventReceiver"+e);  
  22.       }  
  23.   }  


  找到getService()方法,其實現為:

[java]  view plain copy print ?
  1.   //看看它到底是什么  
  2.   private static IAudioService getService()  
  3.     {  
  4.                // 單例模式,大家懂得  
  5.         if (sService != null) {  
  6.             return sService;  
  7.        }  
  8.        //了解Binder機制 以及AIDL文件的使用,就明白了這不過是通過AIDL文件定義的Java層Binder機制  
  9.         //b為IBinder基類接口  
  10.         IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);  
  11.        //強制轉換后,sService不過是一個客戶端對象,IAudioService就是aidl文件定義的接口了  
  12.         sService = IAudioService.Stub.asInterface(b);  
  13.        return sService;  
  14.     }      
  15. //sService對象的聲明  
  16.          private static IAudioService sService; //單例模式,不足為奇了  


         我們知道了AudiaoManager只不過是一個傀儡,所有的方法都是由IAudioService 對象去實現的,通過它的構造方式,

  可以知道它應該是有AIDL文件形成的Binder機制, sService只是客戶端對象,那么它的服務端對象在什么地方呢?

  也就是繼承了IAudioService.Stub樁的類。

 

第三步、接下來我們需要找到該IAudioService.aidl文件和真正的服務端對象  

 

   IAudioService.aidl定義如下:

[java]  view plain copy print ?
  1. package android.media;  
  2.   
  3. import android.content.ComponentName;  
  4. import android.media.IAudioFocusDispatcher;  
  5. /** 
  6.  * {@hide} 
  7.  */  
  8. interface IAudioService {  
  9.       
  10.     void adjustVolume(int direction, int flags);  
  11.     void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags);  
  12.     void adjustStreamVolume(int streamType, int direction, int flags);          
  13.     void setStreamVolume(int streamType, int index, int flags);          
  14.     void setStreamSolo(int streamType, boolean state, IBinder cb);            
  15.     void setStreamMute(int streamType, boolean state, IBinder cb);        
  16.     int getStreamVolume(int streamType);          
  17.     int getStreamMaxVolume(int streamType);         
  18.     void setRingerMode(int ringerMode);          
  19.     int getRingerMode();  
  20.     void setVibrateSetting(int vibrateType, int vibrateSetting);          
  21.     int getVibrateSetting(int vibrateType);          
  22.     boolean shouldVibrate(int vibrateType);  
  23.     void setMode(int mode, IBinder cb);  
  24.     int getMode();  
  25.     oneway void playSoundEffect(int effectType);        
  26.     oneway void playSoundEffectVolume(int effectType, float volume);  
  27.     boolean loadSoundEffects();       
  28.     oneway void unloadSoundEffects();  
  29.     oneway void reloadAudioSettings();  
  30.     void setSpeakerphoneOn(boolean on);  
  31.     boolean isSpeakerphoneOn();  
  32.     void setBluetoothScoOn(boolean on);  
  33.     boolean isBluetoothScoOn();  
  34.     int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb, IAudioFocusDispatcher l, String clientId);  
  35.     int abandonAudioFocus(IAudioFocusDispatcher l, String clientId);          
  36.     void unregisterAudioFocusClient(String clientId);  
  37.     void registerMediaButtonEventReceiver(in ComponentName eventReceiver);   //這個方法是我們需要弄懂的  
  38.     void unregisterMediaButtonEventReceiver(in ComponentName eventReceiver);  //這個方法也是是我們需要弄懂的  
  39.     void startBluetoothSco(IBinder cb);  
  40.     void stopBluetoothSco(IBinder cb);  
  41. }  

    

       真正的服務端對象就是繼承了 IAudioService.Stub 樁的類,AudioService就是該服務端對象,其實AudioManager的

  所有操作都是由AudioService來實現的,它才是真正的老大。


第五步、   AudioService.java

[java]  view plain copy print ?
  1. //AudioService類   
  2. public class AudioService extends IAudioService.Stub {  
  3.     //.....  
  4.     //僅僅列出我們需要的方法  
  5.     //這兒才是真正的注冊MediaButtonReceiver的方法  
  6.     public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {  
  7.         Log.i(TAG, "  Remote Control   registerMediaButtonEventReceiver() for " + eventReceiver);  
  8.   
  9.         synchronized(mRCStack) {  
  10.           //調用它去實現注冊ComponentName  
  11.             pushMediaButtonReceiver(eventReceiver);  
  12.         }  
  13.     }  
  14.       
  15.    //在查看pushMediaButtonReceiver()方法  先理解一下兩個知識點,很重要的。  
  16.     //RemoteControlStackEntry內部類不過是對ComponentName類的進一步封裝(感覺沒必要在加一層進行封裝了)   
  17.     private static class RemoteControlStackEntry {  
  18.         public ComponentName mReceiverComponent;// 屬性  
  19.           //TODO implement registration expiration?  
  20.         //public int mRegistrationTime;  
  21.   
  22.         public RemoteControlStackEntry() {  
  23.         }  
  24.   
  25.         public RemoteControlStackEntry(ComponentName r) {  
  26.             mReceiverComponent = r;// 構造函數賦值給mReceiverComponent對象  
  27.         }  
  28.     }  
  29.       
  30.    //采用了棧存儲結構(先進后出)來保存所有RemoteControlStackEntry對象,也就是保存了ComponentName對象  
  31.     private Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>();  
  32.      
  33.    //回到pushMediaButtonReceiver()查看,這下該撥開雲霧了吧,繼續學習  
  34.    private void pushMediaButtonReceiver(ComponentName newReceiver) {  
  35.      // already at top of stack?  
  36.         //采用了一個棧(前面我們介紹的知識點)來保存所有注冊的ComponentName對象  
  37.         //如果當前棧不為空並且棧頂的對象與新注冊的ComponentName對象一樣,不做任何事,直接返回  
  38.         if (!mRCStack.empty() && mRCStack.peek().mReceiverComponent.equals(newReceiver)) {  
  39.             return;  
  40.         }  
  41.         //獲得mRCStack棧的迭代器  
  42.         Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();  
  43.         //循環  
  44.         while(stackIterator.hasNext()) {  
  45.           RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();  
  46.           //如果當前棧內保存該新注冊的ComponentName對象,將它移除,跳出循環  
  47.             if(rcse.mReceiverComponent.equals(newReceiver)) {  
  48.                 mRCStack.remove(rcse);  
  49.                 break;  
  50.             }  
  51.         }  
  52.       //將新注冊的ComponentName對象放入棧頂  
  53.         mRCStack.push(new RemoteControlStackEntry(newReceiver));  
  54.     }  
  55. }  

 

小結一下: 


         棧(mRCStack)維護了所有CompoentName對象,對每個CompoentName對象,保證它有且僅有一個,

     新注冊的CompoentName對象永遠處於棧頂    


 

 我們看下取消注冊的方法:

[java]  view plain copy print ?
  1. //我們看下取消注冊的方法  
  2. /** see AudioManager.unregisterMediaButtonEventReceiver(ComponentName eventReceiver) */  
  3. public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {  
  4.     Log.i(TAG, "  Remote Control   unregisterMediaButtonEventReceiver() for " + eventReceiver);  
  5.   
  6.     synchronized(mRCStack) {  
  7.          //調用removeMediaButtonReceiver方法去實現  
  8.         removeMediaButtonReceiver(eventReceiver);  
  9.     }  
  10. }  
  11.   
  12. private void removeMediaButtonReceiver(ComponentName newReceiver) {  
  13.     Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();  
  14.     while(stackIterator.hasNext()) {  
  15.          //獲得mRCStack棧的迭代器  
  16.         RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();  
  17.         //如果存在該對象,則移除,跳出循環  
  18.         if(rcse.mReceiverComponent.equals(newReceiver)) {  
  19.             mRCStack.remove(rcse);  
  20.             break;  
  21.         }  
  22.     }  
  23. }  

 

          通過對前面的學習,我們知道了AudioManager內部利用一個棧來管理包括加入和移除ComponentName對象,

    新的疑問來了?這個MEDIA_BUTTON廣播是如何分發的呢 ?

 
         其實,AudioService.java文件中也存在這么一個MediaoButtonReceiver的廣播類,它為系統廣播接收器,即用來接收

  系統的MEDIA_BUTTON廣播,當它接收到了這個MEDIA_BUTTON廣播   ,它會對這個廣播進行進一步處理,這個處理過程

   就是我們需要的弄清楚。

 

MediaButtonBroadcastReceiver 內部類如下:

 

[java]  view plain copy print ?
  1. private class MediaButtonBroadcastReceiver extends BroadcastReceiver {  
  2.     @Override  
  3.     public void onReceive(Context context, Intent intent) {  
  4.         //獲得action ,系統MEDIA_BUTTON廣播來了  
  5.         String action = intent.getAction();  
  6.         //action不正確 直接返回  
  7.         if (!Intent.ACTION_MEDIA_BUTTON.equals(action)) {  
  8.             return;  
  9.         }  
  10.       //獲得KeyEvent對象  
  11.         KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);  
  12.         if (event != null) {  
  13.             // if in a call or ringing, do not break the current phone app behavior  
  14.             // TODO modify this to let the phone app specifically get the RC focus  
  15.             //      add modify the phone app to take advantage of the new API  
  16.             //來電或通話中,不做處理直接返回  
  17.             if ((getMode() == AudioSystem.MODE_IN_CALL) ||(getMode() == AudioSystem.MODE_RINGTONE)) {  
  18.                 return;  
  19.             }  
  20.             synchronized(mRCStack) {  
  21.                 //棧不為空  
  22.                 if (!mRCStack.empty()) {  
  23.                     // create a new intent specifically aimed at the current registered listener  
  24.                     //構造一個Intent對象 ,並且賦予Action和KeyEvent  
  25.                     Intent targetedIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);  
  26.                     targetedIntent.putExtras(intent.getExtras());  
  27.                     //指定該處理Intent的對象為棧頂ComponentName對象的廣播類  
  28.                         targetedIntent.setComponent(mRCStack.peek().mReceiverComponent);  
  29.                     // trap the current broadcast  
  30.                     // 終止系統廣播  
  31.                          abortBroadcast();  
  32.                     //Log.v(TAG, " Sending intent" + targetedIntent);  
  33.                     //手動發送該廣播至目標對象去處理,該廣播不再是系統發送的了  
  34.                         context.sendBroadcast(targetedIntent, null);  
  35.                 }  
  36.                 //假設棧為空,那么所有定義在AndroidManifest.xml的監聽MEDIA_BUTTON的廣播都會處理,  
  37.                 //在此過程中如果有任何應用程注冊了registerMediaButton 該廣播也會立即終止  
  38.             }  
  39.         }  
  40.     }  
  41. }  

 

 總結一下MEDIA_BUTTON廣播: 

    

         AudioManager也就是AudioService服務端對象內部會利用一個棧來管理所有ComponentName對象,所有對象有且僅有一個,

   注冊的ComponentName總是會位於棧頂。

 

         當系統發送MEDIA_BUTTON,系統MediaButtonBroadcastReceiver 監聽到系統廣播,它會做如下處理:

                 1、 如果棧為空,則所有注冊了該Action的廣播都會接受到,因為它是由系統發送的。
                 2、 如果棧不為空,那么只有棧頂的那個廣播能接受到MEDIA_BUTTON的廣播,手動發送了MEDIA_BUTTON

                      廣播,並且指定了目標對象(棧頂對象)去處理該MEDIA_BUTTON 。

 下面分析一下KeyEvent對象里的KeyCode按鍵,可能的按鍵碼有:


       1、KeyEvent.KEYCODE_MEDIA_NEXT
       2、KeyEvent.KEYCODE_HEADSETHOOK 
       3、KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE(已廢除,等同於KEYCODE_HEADSETHOOK)
       4、KeyEvent.KEYCODE_MEDIA_PREVIOUS
       5、KeyEvent.KEYCODE_MEDIA_STOP 
    
    PS : 在我的真機測試中,按下MEDIA_BUTTON只有KEYCODE_HEADSETHOOK可以打印出來了。

 

下面給出一個小DEMO檢驗一下我們之前所做的一切,看看MEDIA_BUTTON是如何處理分發廣播的。

 

   編寫兩個MediaButtonReceiver類用來監聽MEDIA_BUTTON廣播:

 

  1 、China_MBReceiver.java

[java]  view plain copy print ?
  1. package com.qin.mediabutton;  
  2.   
  3. import android.content.BroadcastReceiver;  
  4. import android.content.Context;  
  5. import android.content.Intent;  
  6. import android.util.Log;  
  7. import android.view.KeyEvent;  
  8.   
  9. public class China_MBReceiver extends BroadcastReceiver  {  
  10.   
  11.     private static String TAG = "China_MBReceiver" ;  
  12.     @Override  
  13.     public void onReceive(Context context, Intent intent) {  
  14.         //獲得Action   
  15.         String intentAction = intent.getAction() ;  
  16.         //獲得KeyEvent對象  
  17.         KeyEvent keyEvent = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);  
  18.           
  19.         Log.i(TAG, "Action ---->"+intentAction + "  KeyEvent----->"+keyEvent.toString());  
  20.           
  21.         if(Intent.ACTION_MEDIA_BUTTON.equals(intentAction)){  
  22.             //獲得按鍵字節碼  
  23.             int keyCode = keyEvent.getKeyCode() ;  
  24.             //按下 / 松開 按鈕  
  25.             int keyAction = keyEvent.getAction() ;  
  26.             //獲得事件的時間  
  27.             long downtime = keyEvent.getEventTime();  
  28.               
  29.             //獲取按鍵碼 keyCode   
  30.             StringBuilder sb = new StringBuilder();  
  31.             //這些都是可能的按鍵碼 , 打印出來用戶按下的鍵  
  32.             if(KeyEvent.KEYCODE_MEDIA_NEXT == keyCode){  
  33.                 sb.append("KEYCODE_MEDIA_NEXT");  
  34.             }  
  35.             //說明:當我們按下MEDIA_BUTTON中間按鈕時,實際出發的是 KEYCODE_HEADSETHOOK 而不是 KEYCODE_MEDIA_PLAY_PAUSE  
  36.             if(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ==keyCode){  
  37.                 sb.append("KEYCODE_MEDIA_PLAY_PAUSE");  
  38.             }  
  39.             if(KeyEvent.KEYCODE_HEADSETHOOK == keyCode){  
  40.                 sb.append("KEYCODE_HEADSETHOOK");  
  41.             }  
  42.             if(KeyEvent.KEYCODE_MEDIA_PREVIOUS ==keyCode){  
  43.                 sb.append("KEYCODE_MEDIA_PREVIOUS");  
  44.             }  
  45.             if(KeyEvent.KEYCODE_MEDIA_STOP ==keyCode){  
  46.                 sb.append("KEYCODE_MEDIA_STOP");  
  47.             }  
  48.             //輸出點擊的按鍵碼  
  49.             Log.i(TAG, sb.toString());  
  50.               
  51.         }  
  52.           
  53.     }  
  54.   
  55. }  

 

   2 、England_MBReceiver.java同於China_MBRreceiver ,打印Log TAG= "England_MBReceiver"

   3、在AndroidManifest.xml文件定義:

[java]  view plain copy print ?
  1. <strong>  <receiver android:name=".China_MBReceiver">  
  2.           <intent-filter >  
  3.                 <action android:name="android.intent.action.MEDIA_BUTTON"></action>  
  4.           </intent-filter>  
  5.         </receiver>  
  6.           
  7.          <receiver android:name=".Enaland_MBReceiver">  
  8.           <intent-filter >  
  9.                 <action android:name="android.intent.action.MEDIA_BUTTON"></action>  
  10.           </intent-filter>  
  11.         </receiver></strong>  


4、MainActivity .java 我們通過手動構造一個MEDIA_BUTTON廣播去查看我們的MediaButtonReceiver類的打印信息。

 

[java]  view plain copy print ?
  1. package com.qin.mediabutton;  
  2.   
  3. import android.app.Activity;  
  4. import android.content.ComponentName;  
  5. import android.content.Context;  
  6. import android.content.Intent;  
  7. import android.media.AudioManager;  
  8. import android.os.Bundle;  
  9. import android.view.KeyEvent;  
  10.   
  11. public class MainActivity extends Activity {  
  12.     /** Called when the activity is first created. */  
  13.     @Override  
  14.     public void onCreate(Bundle savedInstanceState) {  
  15.         super.onCreate(savedInstanceState);  
  16.         setContentView(R.layout.main);  
  17.           
  18.         //由於在模擬器上測試,我們手動發送一個MEDIA_BUTTON的廣播,有真機更好處理了  
  19.         Intent mbIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);  
  20.         //構造一個KeyEvent對象  
  21.         KeyEvent keyEvent = new KeyEvent (KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_HEADSETHOOK) ;  
  22.         //作為附加值添加至mbIntent對象中  
  23.         mbIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);  
  24.   
  25.         //此時China_MBReceiver和England_MBReceiver都會接收到該廣播  
  26.         sendBroadcast(mbIntent);  
  27.           
  28.           
  29.         AudioManager mAudioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);  
  30.         //AudioManager注冊一個MediaButton對象  
  31.         ComponentName chinaCN = new ComponentName(getPackageName(),China_MBReceiver.class.getName());  
  32.         //只有China_MBReceiver能夠接收到了,它是出於棧頂的。  
  33.         //不過,在模擬上檢測不到這個效果,因為這個廣播是我們發送的,流程不是我們在上面介紹的。  
  34.         mAudioManager.registerMediaButtonEventReceiver(chinaCN);  
  35.        //sendBroadcast(mbIntent,null);  
  36.     }  
  37.    //當一個Activity/Service死去時,我們需要取消這個MediaoButtonReceiver的注冊,如下  
  38.     protected void onDestroy(){  
  39.         super.onDestroy() ;  
  40.         AudioManager mAudioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);  
  41.         ComponentName chinaCN = new ComponentName(getPackageName(),China_MBReceiver.class.getName());  
  42.         //取消注冊  
  43.         mAudioManager.unregisterMediaButtonEventReceiver(chinaCN);  
  44.     }  
  45. }  

 

       值得注意的一點時,當我們為一個應用程序注冊了MediaoButtonReceiver時,在程序離開時,我們需要取消

  MediaoButtonReceiver的注冊,在onDestroy()調用unregisterMediaButtonEventReceiver()方法就OK,這樣應用程序之間

  的交互就更具邏輯性了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM