一.BroadCastReceiver 簡介
1.廣播接收者( BroadcastReceiver )用於接收廣播 Intent ,廣播 Intent 的發送是通過調用Context.sendBroadcast() 、 Context.sendOrderedBroadcast() 來實現的。通常一個廣播 Intent 可以被訂閱了此Intent 的多個廣播接收者所接收。
2.廣播是一種廣泛運用的在應用程式之間傳輸資訊的機制 。而 BroadcastReceiver 是對發送出來的廣播進行過濾接收並響應的一類組件;
3.生命週期只有十秒左右,如果在 onReceive() 內做超過十秒內的事情,就會報錯 。
每次廣播到來時 , 會重新建立 BroadcastReceiver 對象 , 並且調用 onReceive() 方法 , 執行完以後 , 該對象即被銷毀 . 當 onReceive() 方法在 10 秒內沒有執行完畢, Android 會認為該程式無響應 . 所以在BroadcastReceiver 裡不能做一些比較耗時的操作 , 否側會彈出 ANR(ApplicationNo Response) 的對話方塊 。
4.怎麼用好 BroadcastReceiver ?
如果需要完成一項比較耗時的工作 , 應該通過發送 Intent 給 Service, 由 Service 來完成 . 這裡不能使用子線程來解決 , 因為 BroadcastReceiver 的生命週期很短 , 子線程可能還沒有結束BroadcastReceiver 就先結束了 .BroadcastReceiver 一旦結束 , 此時 BroadcastReceiver 的所在進程很容易在系統需要記憶體時被優先殺死 , 因為它屬於空進程 ( 沒有任何活動組件的進程 ). 如果它的宿主進程被殺死 , 那麼正在工作的子線程也會被殺死 . 所以採用子線程來解決是不可靠的 。如一個代理程式更新其他應用程式某些資料已經下載完畢。BroadcastReceiver 自身並不實現圖形化使用者介面,但是當它收到某個通知後, BroadcastReceiver 可以啟動Activity 作為響應,或者通過 NotificationMananger 提醒使用者,或者啟動 Service 等等。
二.BroadCastReceiver 代碼的實現
用接收簡訊舉例:
第一種方式 :在AndroidManifest.xml中註冊廣播,則全域接受,即在任何的Activity中運行時,如果收到簡訊都會調用改廣播
1.1建立一個SmsReceiver.java,當收到簡訊時調用改廣播
packagecom.yuqiaotech.sms;
importandroid.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;
import android.util.Log;
import android.widget.Toast;
public
classSmsReceiver extends BroadcastReceiver{
public
static final
int NOTIFICATION_ID= 10001;
@Override
publicvoidonReceive(Context context, Intent intent) {
showTost(context,intent);
}
/*
* 使用toast顯示短訊息
*/
privatevoidshowTost(Context context, Intent intent) {
String strRes = "android.provider.Telephony.SMS_RECEIVED";
if (intent.getAction().equals(strRes)) {
StringBuilder sb = new StringBuilder();
Bundle bundle = intent.getExtras();
if (bundle !=null){
Object[] pdus = (Object[]) bundle.get("pdus");
SmsMessage[] msg = new SmsMessage[pdus.length];
for (inti = 0; i < pdus.length;i++) {
msg[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
}
for (SmsMessage currMsg : msg) {
sb.append("您收到了來自:【");
sb.append(currMsg.getDisplayOriginatingAddress());
sb.append("】\n的資訊,內容:");
sb.append(currMsg.getDisplayMessageBody());
}
Toast toast = Toast.makeText(context,
"收到了短訊息: " + sb.toString(),Toast.LENGTH_LONG);
toast.show();
}
}
}
}
1.2在AndroidManifest.xml中註冊廣播
<receiverandroid:name=".SmsReceiver" android:enabled="true">
<intent-filter>
<actionandroid:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
第二種方式 :在代碼中註冊廣播,則局部接受,即只有在註冊的activity運行時,如果收到簡訊才會調用該廣播
2.1隨便建立一個activity,smsTest.java,在onCreate()中添加代碼:
//註冊新的簡訊接收
String SMS_RECEIED="android.provider.Telephony.SMS_RECEIVED ";
IntentFilter filter = new IntentFilter(SMS_RECEIVED);
registerReceiver(newSmsReceiver(), filter);
廣播類型及廣播的收發廣播類型
普通廣播 (Normal broadcasts)
發送一個廣播,所以監聽該廣播的廣播接收者都可以監聽到改廣播。
非同步廣播 , 當處理完之後的Intent ,依然存在,這時候registerReceiver(BroadcastReceiver, IntentFilter) 還能收到他的值,直到你把它去掉 , 不能將處理結果傳給下一個接收者 , 無法終止廣播 .
有序廣播 (Ordered broadcasts)
按照接收者的優先順序順序接收廣播 , 優先順序別在 intent-filter 中的 priority 中聲明 ,-1000 到
1000 之間 , 值越大 , 優先順序越高 . 可以終止廣播意圖的繼續傳播 . 接收者可以篡改內容 .
廣播的收發
該組件接收被廣播的 intent,Context 可以通過 sendBroadcast() 和 sendOrderedBroadcast()
方法實現廣播的發送 。首先在需要發送資訊的地方 ,把要發送的資訊和用於過濾的資訊 ( 如 Action 、 Category) 裝入一個 Intent 對象,然後通過調用 Context.sendBroadcast() 、 sendOrderBroadcast() 或 sendStickyBroadcast() 方法,把 Intent對象以廣播方式發送出去。
使用 sendBroadcast() 或 sendStickyBroadcast() 方法發出去的 Intent ,所有滿足條件的 BroadcastReceiver 都會隨機地執行其 onReceive() 方法
普通廣播的發送和接收:
sendBroadcast(intent);
Intent intent = new Intent( "cn.lenovo.yangguangf " );
sendBroadcast(intent);
priority :這個是 AndroidManifest.xml 中 intent-filter 的參數。
< receiver android:name = ".MyBroadcastReceiver" >
< intent-filter android:priority = "1000" >
< action android:name = "cn.lenovo.yangguangfu" />
</ intent-filter >
</ receiver >
有序廣播的發送和接收:
sendOrderedBroadcast(intent, receiverPermission);
sendOrderedBroadcast(intent, receiverPermission, resultReceiver, scheduler, initialCode, initialData,initialExtras)意圖,廣播,所有匹配的這一意圖將接收機接收廣播。
receiverPermission 這是許可權,一個接收器必須持以接收您的廣播。如果為 null ,不經許可的要求。 resultReceiver 您自己 BroadcastReceiver 來當作最後的廣播接收器。
調度自訂處理常式,用以安排 resultReceiver 回調 ; 如果為 null 將語境中的主線程舉行。
initialCode 一種結果代碼的初始值。通常為 Activity.RESULT_OK 。這個值是 -1 ;為其他 int 型 也可以,如 0,1,2;
initialData 一種結果資料的初始值。通常情況下為空白 , 是 String 類型 ;
initialExtras 一種結果額外的初始值。通常情況下為空白 , 是 Bundle;
1, 該廣播的層級有層級之分,層級數值是在 -1000 到 1000 之間 , 值越大 , 優先順序越高;
2, 同層級接收是先後是隨機的,再到層級低的收到廣播;
3, 同層級接收是先後是隨機的,如果先接收到的把廣播截斷了,同層級的例外的接收者是無法收到該廣播的。(abortBroadcast() )
4 ,能截斷廣播的繼續傳播,進階別的廣播收到該廣播後,可以決定把該鐘廣播是否截斷掉。
5 ,實驗現象,在這個方法發來的廣播中,代碼註冊方式中,收到廣播先後次序為:註明優先順序的、代碼註冊的、沒有優先順序的;如果都沒有優先順序,代碼註冊收到為最先。
非同步廣播的發送和接收:
sendStickyBroadcast(intent);
當處理完之後的Intent ,依然存在,直到你把它去掉。發這個廣播需要許可權<uses-permissionandroid:name="android.permission.BROADCAST_STICKY" />去掉是用這個方法removeStickyBroadcast(intent); 但別忘了在執行這個方法的應用裡面 AndroidManifest.xml同樣要加上面的許可權;
sendStickyOrderedBroadcast(intent, resultReceiver, scheduler, initialCode, initialData,initialExtras)
這個方法具有有序廣播的特性也有非同步廣播的特性;
發送這個廣播要: <uses-permission android:name="android.permission.BROADCAST_STICKY" /> 這個許可權。才能使用這個方法。如果您並不擁有該許可權,將拋出 SecurityException 的。
實驗現象( sendStickyOrderedBroadcast ()中),在這個方法發來的廣播中,代碼註冊方式中,收到廣播先後次序為:註明優先順序的、代碼註冊的、沒有優先順序的;如果都沒有優先順序,代碼註冊收到為最先。
廣播註冊與登出代碼中註冊廣播:
註冊廣播方法一: registerReceiver(BroadcastReceiverreceiver, IntentFilter filter) ,第一個參數是我們要處理廣播的 BroadcastReceiver (廣播接收者,可以是系統的,也可以是自訂的);第二個參數是意圖過濾器。
註冊廣播方法二: registerReceiver(receiver,filter, broadcastPermission, scheduler) ,第一個參數是BroadcastReceiver (廣播接收者,可以是系統的,也可以是自訂的);第二個參數是意圖過濾器;第三個參數是廣播許可權;第四個參數是 Hander ;
注意:許可權重複現象,如果功能資訊清單檔裡註冊了許可權,在該方法再註冊,則 receiver 無法收到廣播,如果 功能資訊清單檔裡沒有註冊了許可權,該方法註冊也無法收到。當該方法沒有註冊許可權,功能清單裡註冊的時候, receiver 能收到廣播。
系統中註冊廣播:(在 AndroidManifest.xml 中 )
< receiver android:name = ".MyBroadcastReceiver" >
< intent-filter android:priority = "900" >
< action android:name = "cn.lenovo.yangguangfu" />
</ intent-filter >
</ receiver >
有時候還要根據發送廣播是否指定許可權,來決定是否要許可權;
廣播登出
// 代碼中登出廣播
unregisterReceiver(mBatteryInfoReceiver);