BroadcastReceiver

BroadcastReceiver 用於異步接收廣播Intent。主要有兩大類,用於接收廣播的: android

·         正常廣播 Normal broadcasts(用 Context.sendBroadcast()發送)是徹底異步的。它們都運行在一個未定義的順序,一般是在同一時間。這樣會更有效,但意味着receiver不能包含所要使用的結果或停止的API   app

·         有序廣播 Ordered broadcasts(用 Context.sendOrderedBroadcast()發送)每次被髮送到一個receiver。所謂有序,就是每一個receiver執行後能夠傳播到下一個receiver,也能夠徹底停止傳播——不傳播給其餘receiver。 而receiver運行的順序能夠經過matched intent-filter 裏面的android:priority來控制,當priority優先級相同的時候,Receiver以任意的順序運行。 異步

 

    要注意的是,即便是Normal broadcasts,系統在某些狀況下可能會恢復到一次傳播給一個receiver。 特別是receiver可能須要建立一個進程,爲了不繫統超載,只能一次運行一個receiver ide

 

    Broadcast Receiver 並無提供可視化的界面來顯示廣播信息。可使用NotificationNotification Manager來實現可視化的信息的界面,顯示廣播信息的內容,圖標及震動信息。 函數

 

生命週期 ui

    一個BroadcastReceiver 對象只有在被調用onReceive(Context, Intent)的纔有效的,當從該函數返回後,該對象就無效的了,結束生命週期。 spa

    所以從這個特徵能夠看出,在所調用的onReceive(Context, Intent)函數裏,不能有過於耗時的操做,不能使用線程來執行。對於耗時的操做,請start service來完成。由於當獲得其餘異步操做所返回的結果時,BroadcastReceiver 可能已經無效了。 線程

 

發送廣播 orm

    事件的廣播比較簡單,構建Intent對象,可調用sendBroadcast(Intent)方法將廣播發出。另外還有sendOrderedBroadcast()sendStickyBroadcast()等方法,請查閱API Doc xml

    1.new Intent with action name 

        Intent intent = new Intent(String action);

      或者 只是new Intent, 而後

        intent.setAction(String action);

 

    2.set data等準備好了後,in activity,

        sendBroadcast(Intent); // 發送廣播

 

接收廣播

    經過定義一個繼承BroadcastReceiver類來實現,繼承該類後覆蓋其onReceiver方法,並在該方法中響應事件。

public class SMSReceiver extends BroadcastReceiver {

        @Override
        
public void onReceive(Context context, Intent intent)
                
// get data from SMS intent
                Bundle bundle = intent.getExtras();
                
if (bundle != null){
                        
// get message by "pdus"
                        Object[] objArray = (Object[]) bundle.get(
"pdus");

                        
// rebuild SMS
                        SmsMessage[] messages =
new SmsMessage[objArray.length];
                        
for (int i=0; i < objArray.length; i++){
                                messages[i] = SmsMessage.createFromPdu((
byte[])objArray[i]);

                                StringBuilder str =
new StringBuilder("from: ");
                                str.append(messages[i].getDisplayOriginatingAddress());
                                str.append(
"\nmessage:\n");
                                str.append(messages[i].getDisplayMessageBody());

                                Toast.makeText(context, str.toString(), Toast.LENGTH_LONG)
                                                .show();
                        }
                }
        }
}

 

註冊Receiver

   註冊有兩種方式:
   1.
靜態方式,在AndroidManifest.xmlapplication裏面定義receiver並設置要接收的action

<receiver android:name=".SMSReceiver">
        
<intent-filter>
                
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
        
</intent-filter>
</receiver>


   2.
動態方式, activity裏面調用函數來註冊,和靜態的內容差很少。一個形參是receiver,另外一個是IntentFilter,其中裏面是要接收的action

public class HelloDemo extends Activity {    
        
private BroadcastReceiver receiver;    

        @Override
        
protected void onStart() {
                
super.onStart();

                receiver =
new CallReceiver();
                registerReceiver(receiver,
new IntentFilter("android.intent.action.PHONE_STATE"));
        }

        @Override
        
protected void onStop() {
                unregisterReceiver(receiver);
                
super.onStop();
        }
}

   一個receiver能夠接收多個action的,便可以有多個intent-filter,須要在onReceive裏面對intent.getAction(action name)進行判斷。
 

    我的推薦使用靜態註冊方式,由系統來管理receiver,並且程序裏的全部receiver,能夠在xml裏面一目瞭然。而動態註冊方式,隱藏在代碼中,比較難發現。
   
並且動態註冊,須要特別注意的是,在退出程序前要記得調用
Context.unregisterReceiver()方法。通常在activityonStart()裏面進行註冊, onStop()裏面進行註銷。官方提醒,若是在Activity.onResume()裏面註冊了,就必須在Activity.onPause()註銷。

 

Permission權限
 
要接收某些action,須要在AndroidManifest.xml裏面添加相應的permission。例如接收SMS:

<uses-permission android:name="android.permission.RECEIVE_SMS" />



下面給出動態註冊的接收來電的廣播處理的CallReceiver的代碼:

   一種方式是直接讀取intent.getStringExtra("incoming_number")來獲取來電號碼:

public class CallReceiver extends BroadcastReceiver {

        @Override
        
public void onReceive(Context context, Intent intent) {
                TelephonyManager teleManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
                
                
switch(teleManager.getCallState()){
                
case TelephonyManager.CALL_STATE_RINGING: //響鈴
                        Toast.makeText(context,
"Ringing: " + intent.getStringExtra("incoming_number"), Toast.LENGTH_LONG).show();
                        
break;
                
case TelephonyManager.CALL_STATE_OFFHOOK: //接聽
                        Toast.makeText(context,
"OffHook: " + intent.getStringExtra("incoming_number"), Toast.LENGTH_LONG).show();
                        
break;
                
case TelephonyManager.CALL_STATE_IDLE: //掛斷
                        Toast.makeText(m_context,
"Idle: " + incomingNumber, Toast.LENGTH_LONG).show();
                        
break;
                }
        }
}

   在運行時,發現除了響鈴時能夠獲取來電號碼,接聽和掛斷都不能成功獲取的,顯示爲null

 

   另外一種方式是經過PhoneStateListeneronCallStateChanged來監聽狀態的變化:

public class CallReceiver extends BroadcastReceiver {

        
private Context m_context;
        @Override
        
public void onReceive(Context context, Intent intent) {
                m_context = context;
                TelephonyManager teleManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
                teleManager.listen(
new PhoneStateListener(){

                        @Override
                        
public void onCallStateChanged(int state, String incomingNumber) {
                                
switch(state){
                                
case TelephonyManager.CALL_STATE_RINGING: //響鈴
                                        Toast.makeText(m_context,
"Ringing: " + incomingNumber, Toast.LENGTH_LONG)
                                                                .show();
                                        
break;
                                
case TelephonyManager.CALL_STATE_OFFHOOK: //接聽
                                        Toast.makeText(m_context,
"OffHook: " + incomingNumber, Toast.LENGTH_LONG)
                                        .show();
                                        
break;
                                
case TelephonyManager.CALL_STATE_IDLE: //掛斷
                                        Toast.makeText(m_context,
"Idle: " + incomingNumber, Toast.LENGTH_LONG)
                                        .show();
                                        
break;
                                }
                        }}, PhoneStateListener.LISTEN_CALL_STATE);  
        }
}

    運行時也發現incomingNumber在接聽和掛斷時獲取爲blank

    由於這裏監聽的是通話的狀態變化,因此這個receiver會被調用3次。

 

    監聽通話狀態須要加上權限:

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

 

===========

小結:

1. 對於sendBroadCastintent對象,須要設置其action name 
2.
推薦使用顯式指明receiver,在配置文件AndroidManifest.xml指明; 
3.
一個receiver能夠接收多個action; 

4. 每次接收廣播都會從新生成一個接收廣播的對象,再次調用onReceive

5. BroadCast 中儘可能不要處理太多邏輯問題,建議複雜的邏輯交給Activity 或者 Service 去處理。

相關文章
相關標籤/搜索