BroadcastReceiver用於接收程序(包括系統程序和通常應用)經過sendBroadcast()方法發出的Broadcast intents。java
1) 建立須要啓動BroadcastReceiver的Intent。android
2) 調用Context的sendBroadcast
()或sendOrderedBroadcast
()方法來啓動指定的BroadcastReceiver。其中sendBroadcast
發送的是普通廣播,sendOrderedBroadcast發送的是有序廣播。緩存
當應用發出一個Broadcast Intent以後所匹配該Intent的組件均可能被啓動。異步
第一步:建立BroadcastReceiver的子類:ide
因爲BroadcastReceiver本質上是一種監聽器,因此建立BroadcastReceiver的方法也很是簡單,只須要建立一個BroadcastReceiver的子類而後重寫onReceive (Context context, Intentintent)方法便可。ui
具體代碼以下:this
public class MyBroadcastReceiver extends BroadcastReceiver { public static final String TAG = "BroadcastReceiverDemo" ; @Override public void onReceive(Context context, Intent intent) { String msg=intent.getExtras().get("msg").toString(); Log.i(TAG, "msg:"+msg); } }
第二步:註冊BroadcastReceiverspa
一旦實現了BroadcastReceiver,接下就應該指定該BroadcastReceiver能匹配的Intent即註冊BroadcastReceiver。註冊BroadcastReceiver的方式有兩種:.net
①靜態註冊:這種方法是在配置AndroidManifest.xml配置文件中註冊,經過這種方式註冊的廣播爲常駐型廣播,也就是說若是應用程序關閉了,有相應事件觸發,程序仍是會被系統自動調用運行。例如:debug
<!-- 在配置文件中註冊BroadcastReceiver可以匹配的Intent --> <receiver android:name=".MyBroadcastReceiver"> <intent-filter> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </receiver>
②動態註冊:這種方法是經過代碼在.Java文件中進行註冊。經過這種方式註冊的廣播爲很是駐型廣播,即它會跟隨Activity的生命週期,因此在Activity結束前咱們須要調用unregisterReceiver(receiver)方法移除它。例如:
//經過代碼的方式動態註冊MyBroadcastReceiver MyBroadcastReceiver receiver=new MyBroadcastReceiver(); IntentFilter filter=new IntentFilter(); filter.addAction("android.intent.action.MyBroadcastReceiver"); //註冊receiver registerReceiver(receiver, filter);
注意:若是咱們在Activity中註冊了BroadcastReceiver,當這個Activity銷燬的時候要主動撤銷註冊不然會出現異常。方法以下:
@Override protected void onDestroy() { super.onDestroy(); //當Activity銷燬的時候取消註冊BroadcastReceiver unregisterReceiver(receiver); }
BroadcastReceiver的生命週期,從對象調用它開始,到onReceiver方法執行完成以後結束。另外,每次廣播被接收後會從新建立BroadcastReceiver對象,並在onReceiver方法中執行完就銷燬,若是BroadcastReceiver的onReceiver方法中不能在10秒內執行完成,Android會出現ANR異常。因此不要在BroadcastReceiver的onReceiver方法中執行耗時的操做。
若是須要在BroadcastReceiver中執行耗時的操做,能夠經過Intent啓動Service來完成。但不能綁定Service。
特別是,您可能沒法從一個BroadcastReceiver中顯示一個對話框,或綁定到服務。對於前者,則應該使用NotificationManager的API。對於後者,你可使用Context.startService()來啓動一個Service。
Broadcast的類型有兩種:普通廣播和有序廣播。
Normal broadcasts(普通廣播):Normal broadcasts是徹底異步的能夠同一時間被全部的接收者接收到。消息的傳遞效率比較高。但缺點是接收者不能講接收的消息的處理信息傳遞給下一個接收者也不能中止消息的傳播。
Ordered broadcasts(有序廣播):Ordered broadcasts的接收者按照必定的優先級進行消息的接收。如:A,B,C的優先級依次下降,那麼消息先傳遞給A,在傳遞給B,最後傳遞給C。優先級別聲明在中,取值爲[-1000,1000]數值越大優先級別越高。優先級也可經過filter.setPriority(10)方式設置。 另外Ordered broadcasts的接收者能夠經過abortBroadcast()的方式取消廣播的傳播,也能夠經過setResultData和setResultExtras方法將處理的結果存入到Broadcast中,傳遞給下一個接收者。而後,下一個接收者經過getResultData()和getResultExtras(true)接收高優先級的接收者存入的數據。
1)靜態註冊 發送廣播:
public class MainActivity extends Activity implements OnClickListener{ private Button btnSend,btnSend2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_broadcast); btnSend = (Button)findViewById(R.id.btnSend); btnSend2 = (Button)findViewById(R.id.btnSend2); btnSend.setOnClickListener(this); btnSend2.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btnSend: //沒法經過abortBroadcast()的方式中止廣播的傳播, //也沒法往Broadcast中存入數據由於它是異步的 //若是往Broadcast中存入數據會拋異常 Intent intent=new Intent(); intent.setAction("android.intent.action.MyBroadcastReceiver"); intent.putExtra("msg", "這是一個普通的廣播"); sendBroadcast(intent); break; case R.id.btnSend2: //1.能夠經過abortBroadcast可終止廣播的傳播 //2.按優先級的不一樣,優先接收到Broadcast的Receiver可經過 //setResultExtras(Bundle)方法將處理結果存入Broadcast中, //下一個Receiver 經過 Bundle bundle=getResultExtras(true)方法 //獲取上一個 Receiver傳來的數據. Intent intent2=new Intent(); intent2.setAction("android.intent.action.OrderedBroadcastReceiver"); intent2.putExtra("msg", "這是一個有序的廣播"); sendOrderedBroadcast(intent2, null); break; default: break; } } }
MyBroadcastReceiver.java:接收廣播
public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String msg=intent.getExtras().get("msg").toString(); System.out.println("MyBroadcastReceiver收到Action名爲:"+intent.getAction().toString() + "\n消息的內容是:"+msg); } }
FirstBroadcastReceiver.java接收廣播
public class FirstBroadcastReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { String msg=intent.getExtras().get("msg").toString(); setResultData("你好我是第一個廣播!"); System.out.println("FirstBroadcastReceiver收到Action名爲:" + intent.getAction().toString() + "\n消息的內容是:"+msg); //中止廣播 //abortBroadcast(); } }
SecondBroadcastReceiver.java接收廣播
public class SecondBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String msg=intent.getExtras().get("msg").toString(); String result=getResultData(); System.out.println("SecondBroadcastReceiver收到Action名爲:"+intent.getAction().toString() +"\n消息的內容是:"+msg+"\n上一個接受者傳來的reult:"+result); } }
配置文件AndroidManifest.xml:
<!-- 在配置文件中註冊MyBroadcastReceiver可以匹配的Intent --> <receiver android:name=".MyBroadcastReceiver"> <intent-filter> <action android:name="android.intent.action.MyBroadcastReceiver"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </receiver> <!-- 在配置文件中註冊SecondBroadcastReceiver可以匹配的Intent --> <!--優先級的設定 FirstBroadcastReceiver大於SecondBroadcastReceiver,優先級的範圍-1000~1000 --> <receiver android:name=".FirstBroadcastReceiver"> <intent-filter android:priority="200"> <action android:name="android.intent.action.OrderedBroadcastReceiver"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </receiver> <receiver android:name=".SecondBroadcastReceiver"> <intent-filter android:priority="100"> <action android:name="android.intent.action.OrderedBroadcastReceiver"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </receiver>
界面:
日誌打印:
點擊普通廣播
點擊有序廣播
2)動態註冊 發送廣播 以短信接收爲例:
public class MainActivity extends ActionBarActivity { private MyBroadcastReceiver myBroadcastReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myBroadcastReceiver = new MyBroadcastReceiver(); findViewById(R.id.btn1).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { IntentFilter filter=new IntentFilter(); filter.addAction("android.provider.Telephony.SMS_RECEIVED"); registerReceiver(myBroadcastReceiver, filter); System.out.println("註冊了廣播"); } }); findViewById(R.id.btn2).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { unregisterReceiver(myBroadcastReceiver); System.out.println("銷燬了廣播"); } }); } }
public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { System.out.println("MyBroadcastReceiver收到Action名爲:"+intent.getAction().toString()); } }
不須要在AndroidManifest.xml配置文件中註冊,不過使用帶短信,須要加上短信權限
<uses-permission android:name="android.permission.RECEIVE_SMS"/
效果圖:
先註冊廣播,而後在Emulator Control中發短信:
若是不知道這步在哪裏,請看 Android模擬器用命令和DDMS模擬來電和短信
日誌打印:
如:ACTION_TIME_TICK,系統時鐘廣播,系統每分鐘都會發送一個這樣的廣播,若是在應用開發中,有些邏輯依賴於系統時鐘,能夠註冊一個廣播接收者。這是一個受保護的action,只有系統才能發送這個廣播,而且,在manifest文件中註冊的廣播接收者不能接收到該廣播,若要接收該廣播,必須在代碼中註冊廣播接收者
registerReceiver(new BroadcastReceiver(){ @Override public void onReceive(Context context, Intent intent) { Log.i("xxxx", "TIME_TICK"); } },new IntentFilter(Intent.ACTION_TIME_TICK));
Intent.ACTION_AIRPLANE_MODE_CHANGED
//關閉或打開飛行模式時的廣播
Intent.ACTION_BATTERY_CHANGED
//充電狀態,或者電池的電量發生變化
//電池的充電狀態、電荷級別改變,不能經過組建聲明接收這個廣播,只有經過Context.registerReceiver()註冊
Intent.ACTION_BATTERY_LOW
//表示電池電量低
Intent.ACTION_BATTERY_OKAY
//表示電池電量充足,即從電池電量低變化到飽滿時會發出廣播
Intent.ACTION_BOOT_COMPLETED
//在系統啓動完成後,這個動做被廣播一次(只有一次)。
Intent.ACTION_CAMERA_BUTTON
//按下照相時的拍照按鍵(硬件按鍵)時發出的廣播
Intent.ACTION_CLOSE_SYSTEM_DIALOGS
//當屏幕超時進行鎖屏時,當用戶按下電源按鈕,長按或短按(無論有沒跳出話框),進行鎖屏時,android系統都會廣播此Action消息
Intent.ACTION_CONFIGURATION_CHANGED
//設備當前設置被改變時發出的廣播(包括的改變:界面語言,設備方向,等,請參考Configuration.java)
Intent.ACTION_DATE_CHANGED
//設備日期發生改變時會發出此廣播
Intent.ACTION_DEVICE_STORAGE_LOW
//設備內存不足時發出的廣播,此廣播只能由系統使用,其它APP不可用?
Intent.ACTION_DEVICE_STORAGE_OK
//設備內存從不足到充足時發出的廣播,此廣播只能由系統使用,其它APP不可用?
Intent.ACTION_DOCK_EVENT
//發出此廣播的地方frameworks\base\services\java\com\android\server\DockObserver.java
Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
//移動APP完成以後,發出的廣播(移動是指:APP2SD)
Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE
//正在移動APP時,發出的廣播(移動是指:APP2SD)
Intent.ACTION_GTALK_SERVICE_CONNECTED
//Gtalk已創建鏈接時發出的廣播
Intent.ACTION_GTALK_SERVICE_DISCONNECTED
//Gtalk已斷開鏈接時發出的廣播
Intent.ACTION_HEADSET_PLUG
//在耳機口上插入耳機時發出的廣播
Intent.ACTION_INPUT_METHOD_CHANGED
//改變輸入法時發出的廣播
Intent.ACTION_LOCALE_CHANGED
//設備當前區域設置已更改時發出的廣播
Intent.ACTION_MANAGE_PACKAGE_STORAGE
//
Intent.ACTION_MEDIA_BAD_REMOVAL
//未正確移除SD卡(正確移除SD卡的方法:設置--SD卡和設備內存--卸載SD卡),但已把SD卡取出來時發出的廣播
//廣播:擴展介質(擴展卡)已經從 SD 卡插槽拔出,可是掛載點 (mount point) 還沒解除 (unmount)
Intent.ACTION_MEDIA_BUTTON
//按下"Media Button" 按鍵時發出的廣播,假若有"Media Button"按鍵的話(硬件按鍵)
Intent.ACTION_MEDIA_CHECKING
//插入外部儲存裝置,好比SD卡時,系統會檢驗SD卡,此時發出的廣播?
Intent.ACTION_MEDIA_EJECT
//已拔掉外部大容量儲存設備發出的廣播(好比SD卡,或移動硬盤),無論有沒有正確卸載都會發出此廣播?
//廣播:用戶想要移除擴展介質(拔掉擴展卡)。
Intent.ACTION_MEDIA_MOUNTED
//插入SD卡而且已正確安裝(識別)時發出的廣播
//廣播:擴展介質被插入,並且已經被掛載。
Intent.ACTION_MEDIA_NOFS
//
Intent.ACTION_MEDIA_REMOVED
//外部儲存設備已被移除,無論有沒正確卸載,都會發出此廣播?
// 廣播:擴展介質被移除。
Intent.ACTION_MEDIA_SCANNER_FINISHED
//廣播:已經掃描完介質的一個目錄
Intent.ACTION_MEDIA_SCANNER_SCAN_FILE
//
Intent.ACTION_MEDIA_SCANNER_STARTED
//廣播:開始掃描介質的一個目錄
Intent.ACTION_MEDIA_SHARED
// 廣播:擴展介質的掛載被解除 (unmount),由於它已經做爲 USB 大容量存儲被共享。
Intent.ACTION_MEDIA_UNMOUNTABLE
//
Intent.ACTION_MEDIA_UNMOUNTED
// 廣播:擴展介質存在,可是尚未被掛載 (mount)。
Intent.ACTION_NEW_OUTGOING_CALL
//
Intent.ACTION_PACKAGE_ADDED
//成功的安裝APK以後
//廣播:設備上新安裝了一個應用程序包。
//一個新應用包已經安裝在設備上,數據包括包名(最新安裝的包程序不能接收到這個廣播)
Intent.ACTION_PACKAGE_CHANGED
//一個已存在的應用程序包已經改變,包括包名
Intent.ACTION_PACKAGE_DATA_CLEARED
//清除一個應用程序的數據時發出的廣播(在設置--應用管理--選中某個應用,以後點清除數據時?)
//用戶已經清除一個包的數據,包括包名(清除包程序不能接收到這個廣播)
Intent.ACTION_PACKAGE_INSTALL
//觸發一個下載而且完成安裝時發出的廣播,好比在電子市場裏下載應用?
//
Intent.ACTION_PACKAGE_REMOVED
//成功的刪除某個APK以後發出的廣播
//一個已存在的應用程序包已經從設備上移除,包括包名(正在被安裝的包程序不能接收到這個廣播)
Intent.ACTION_PACKAGE_REPLACED
//替換一個現有的安裝包時發出的廣播(無論如今安裝的APP比以前的新仍是舊,都會發出此廣播?)
Intent.ACTION_PACKAGE_RESTARTED
//用戶從新開始一個包,包的全部進程將被殺死,全部與其聯繫的運行時間狀態應該被移除,包括包名(從新開始包程序不能接收到這個廣播)
Intent.ACTION_POWER_CONNECTED
//插上外部電源時發出的廣播
Intent.ACTION_POWER_DISCONNECTED
//已斷開外部電源鏈接時發出的廣播
Intent.ACTION_PROVIDER_CHANGED
//
Intent.ACTION_REBOOT
//重啓設備時的廣播
Intent.ACTION_SCREEN_OFF
//屏幕被關閉以後的廣播
Intent.ACTION_SCREEN_ON
//屏幕被打開以後的廣播
Intent.ACTION_SHUTDOWN
//關閉系統時發出的廣播
Intent.ACTION_TIMEZONE_CHANGED
//時區發生改變時發出的廣播
Intent.ACTION_TIME_CHANGED
//時間被設置時發出的廣播
Intent.ACTION_TIME_TICK
//廣播:當前時間已經變化(正常的時間流逝)。
//當前時間改變,每分鐘都發送,不能經過組件聲明來接收,只有經過Context.registerReceiver()方法來註冊
Intent.ACTION_UID_REMOVED
//一個用戶ID已經從系統中移除發出的廣播
//
Intent.ACTION_UMS_CONNECTED
//設備已進入USB大容量儲存狀態時發出的廣播?
Intent.ACTION_UMS_DISCONNECTED
//設備已從USB大容量儲存狀態轉爲正常狀態時發出的廣播?
Intent.ACTION_USER_PRESENT
//
Intent.ACTION_WALLPAPER_CHANGED
//設備牆紙已改變時發出的廣播
例子1:Android開機廣播和關機廣播
編寫一個繼承BroadcastReceiver的類,接受系統啓動關閉廣播。代碼以下:
public class LaunchReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { System.out.println("系統啓動完畢"); } }
public class ShutdownReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { System.out.println("系統要關閉了"); } }
<receiver android:name=".LaunchReceiver"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"/> </intent-filter> </receiver> <receiver android:name=".ShutdownReceiver"> <intent-filter> <action android:name="android.intent.action.ACTION_SHUTDOWN"/> </intent-filter> </receiver>
同時應添加所須要的權限:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
關機日誌打印:
開機日誌打印:
例子2:經過終止廣播 阻止用戶收到短信
系統收到短信,發出的廣播屬於有序廣播。若是想阻止用戶收到短信,可自定義Receiver,設置高優先級,率先得到接收短信的廣播,並終止廣播。接收短信的廣播名android.provider.Telephony.SMS_RECEIVED。注意:程序一旦在某個模擬器運行,將一直阻止短信,只有註釋掉abortBroadcast(),從新運行,方可正常。
public class MySmsResevicer extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { System.out.println("on receive"); abortBroadcast(); } }
<receiver android:name=".MySmsResevicer"> <intent-filter android:priority="1000"> <action android:name="android.provider.Telephony.SMS_RECEIVED"/> </intent-filter> </receiver>
abortBroadcast ():
這個方法能夠截獲由 sendOrderedBroadcast () 發送來的 廣播,讓其它廣播接收者沒法收到這個廣播。
clearAbortBroadcast ()
這個方法是針對上面的 abortBroadcast() 方法的,用於取消截獲廣播。這樣它的下一級廣播接收者就可以收到該廣播了。
getAbortBroadcast ()
這個方法做用是:判斷是否調用了 abortBroadcast (),若是先調用 abortBroadcast (),接着再調用 getAbortBroadcast (),將返回 true; 若是在調用 abortBroadcast() 、 clearAbortBroadcast ()
getAbortBroadcast (),將返回 false;
public final boolean getDebugUnregister ()
Since: API Level 1
Return the last value given to setDebugUnregister(boolean) .
getResultCode ()
若是用下面四個方法發送得廣播,返回碼爲: -1 ;
// sendBroadcast(intent);
// sendBroadcast(intent, receiverPermission);
// sendOrderedBroadcast(intent, receiverPermission);
// sendStickyBroadcast(intent);
若是用下面兩個方法發送得廣播,返回碼爲:根據你設置 initialCode 的數字是多少就是多少;
// sendStickyOrderedBroadcast(intent, resultReceiver, scheduler,
// initialCode, initialData, initialExtras)
// sendOrderedBroadcast(intent, receiverPermission, resultReceiver,
// scheduler, initialCode, initialData, initialExtras)
getResultData ()
獲得發送廣播時設置的 initialData 的數據;
getResultExtras (boolean makeMap)
If true then a new empty Map will be made for you if the current Map is null; if false you should be prepared to receive a null Map.
獲得由
sendStickyOrderedBroadcast(intent, resultReceiver, scheduler,
// initialCode, initialData, initialExtras) ;
// sendOrderedBroadcast(intent, receiverPermission, resultReceiver,
// scheduler, initialCode, initialData, initialExtras)
中 initialExtras 傳入的參數。
實驗:我用上面兩個方法發了 initialExtras (這個一個 Bundle )傳入的參數時,只要不爲空,那麼 makeMap 是否爲 true 和 false 都可以獲得數據。
isInitialStickyBroadcast ()
Returns true if the receiver is currently processing the initial value of a sticky broadcast -- that is, the value that was last broadcast and is currently held in the sticky cache, so this is not directly the result of a broadcast right now.
若是廣播接收者是目前處理的一個宿主的廣播的初始值,將返回 true , - 也就是說,這個值是最後的廣播出的值,目前正在舉行的宿主緩存,因此這並非直接致使瞭如今的廣播。
實驗:在第三個應用中調用這個方法,不管你用哪一種方式發送廣播,這個方法獲得的老是 false ;在發送廣播 的 resultReceiver 廣播接收者裏面調用,獲得的也是 false ;
isOrderedBroadcast ()
sendStickyOrderedBroadcast(intent, resultReceiver, scheduler,
initialCode, initialData, initialExtras)
上面這個方法發送時,獲得的是 true;
判斷是不是有序廣播;
onReceive (Context context, Intent intent)
public IBinder peekService (Context myContext, Intent service)
Provide a binder to an already-running service. This method is synchronous and will not start the target service if it is not present, so it is safe to call from onReceive.
Parameters:
myContext The Context that had been passed to onReceive(Context, Intent)
service The Intent indicating the service you wish to use. See Context.startService(Intent) for more information.
setDebugUnregister (boolean debug)
Control inclusion of debugging help for mismatched calls to {@ Context#registerReceiver(BroadcastReceiver, IntentFilter) Context.registerReceiver()}. If called with true, before given to registerReceiver(), then the callstack of the following Context.unregisterReceiver()
call is retained, to be printed if a later incorrect unregister call is made. Note that doing this requires retaining information about the BroadcastReceiver for