一、Android廣播機制概述
Android廣播分為兩個方面:廣播發送者和廣播接收者,通常情況下,BroadcastReceiver指的就是廣播接收者(廣播接收器)。
廣播作為Android元件間的通信方式,可以使用的場景如下:
- 同一app内部的同一元件内的消息通信(單個或多個線程之間);
- 同一app内部的不同元件之間的消息通信(單個程序);
- 同一app具有多個程序的不同元件之間的消息通信;
- 不同app之間的元件之間消息通信;
- Android系統在特定情況下與App之間的消息通信。
二、廣播的分類
- Normal Broadcast(普通廣播):通常調用sendBroadcast(Intent)(Intent, String)方法發送
- System Broadcast(系統廣播):發生各種事件時,系統自動發送
- Ordered Broadcast(有序廣播):調用sendOrderedBroadcast(Intent, String)方法發送
- Local Broadcast(本地廣播):調用LocalBroadcastManager.sendBroadcast(intent)方法發送
- Sticky Broadcast(粘性廣播):已棄用(API 21)
1).Normal Broadcast:普通廣播
此處将普通廣播界定為:開發者自己定義的intent,以context.sendBroadcast_"AsUser"(intent, ...)形式。具體可以使用的方法有:
sendBroadcast(intent)
sendBroadcast(intent,receiverPermission)
sendBroadcastAsUser(intent,userHandler)
sendBroadcastAsUser(intent,userHandler,receiverPermission)。
普通廣播會被注冊了的相應的感興趣(intent-filter比對)接收,且順序是無序的。如果發送廣播時有相應的權限要求,BroadCastReceiver如果想要接收此廣播,也需要有相應的權限。
- 發送示例如下:
Intent intent = new Intent();
intent.setAction(BROADCAST_ACTION);
//最普通的發送方式
sendBroadcast(intent);
//附帶權限的發送方式,聲明此權限的BroadcastReceiver才能接收此廣播
sendBroadcast(intent,RECEIVER_PREMISSION);
//以下兩種不常見,是因為隻有預裝在系統映像中的程式才能使用,否則無法使用
//指明接收人的發送方式
sendBroadcastAsUser(intent,USER_HANDLER);
//指明接收人以及對應權限的發送方式
sendBroadcastAsUser(intent,USER_HANDLER,RECEIVER_PREMISSION);
- 若被注冊了的
注冊的BroadCastReceiver
的intentFilter
與上述比對,則會接收此廣播,且順序是無序的。如果發送時有相應的權限要求,則action
隻有擁有相應的權限才能接受。BroadCastReceiver
<receiver
android:name=".MyBroadcastReceiver"
android:permission="RECEIVER_PREMISSION">
<intent-filter>
<action android:name="BROADCAST_ACTION"/>
</intent-filter>
</receiver>
2).System Broadcast: 系統廣播
Android系統中内置了多個系統廣播,隻要涉及到手機的基本操作,基本上都會發出相應的系統廣播。
如:開啟啟動,網絡狀态改變,拍照,螢幕關閉與開啟,點亮不足等等。每個系統廣播都具有特定的intent-filter,其中主要包括具體的action,系統廣播發出後,将被相應的BroadcastReceiver接收。系統廣播在系統内部當特定事件發生時,有系統自動發出。
文末提供詳細系統廣播清單,不包含使用說明(位于SDK下boradcast_action.txt ),請自行查找Google官方文檔
3).Ordered broadcast:有序廣播
有序廣播的有序廣播中的“有序”是針對廣播接收者而言的,指的是發送出去的廣播被BroadcastReceiver按照先後循序接收。有序廣播的定義過程與普通廣播無異,隻是其的主要發送方式變為:sendOrderedBroadcast(intent, receiverPermission, ...)。
- 定義過程與普通廣播一樣,調用
,同樣也有對應的sendOrderedBroadcast()
方法,隻不過同樣針對于預裝在系統映像的應用。sendOrderedBroadcastAsUser()
對于有序廣播,其主要特點總結如下:
1>多個具目前已經注冊且有效的BroadcastReceiver接收有序廣播時,是按照先後順序接收的,先後順序判定标準遵循為:将目前系統中所有有效的動态注冊和靜态注冊的BroadcastReceiver按照priority屬性值從大到小排序,對于具有相同的priority的動态廣播和靜态廣播,動态廣播會排在前面。
-
值不同:由大到小排序priority
-
值相同:動态注冊優于靜态注冊priority
2>先接收的BroadcastReceiver可以對此有序廣播進行截斷,使後面的BroadcastReceiver不再接收到此廣播,也可以對廣播進行修改,使後面的BroadcastReceiver接收到廣播後解析得到錯誤的參數值。當然,一般情況下,不建議對有序廣播進行此類操作,尤其是針對系統中的有序廣播。
- 按順序接收
- 允許優先級高的
截斷廣播。BroadcastReceiver
- 允許優先級高的
修改廣播BroadcastReceiver
4).Sticky Broadcast:粘性廣播(在 android 5.0/api 21中deprecated,不再推薦使用,相應的還有粘性有序廣播,同樣已經deprecated)
5).Local Broadcast:App應用内廣播(此處的App應用以App應用程序為界)
Android中的廣播可以跨程序甚至跨App直接通信,且注冊是exported對于有intent-filter的情況下預設值是true,由此将可能出現安全隐患如下:
1.其他App可能會針對性的發出與目前App intent-filter相比對的廣播,由此導緻目前App不斷接收到廣播并處理;
2.其他App可以注冊與目前App一緻的intent-filter用于接收廣播,擷取廣播具體資訊。
無論哪種情形,這些安全隐患都确實是存在的。由此,最常見的增加安全性的方案是:
1.對于同一App内部發送和接收廣播,将exported屬性人為設定成false,使得非本App内部發出的此廣播不被接收;
2.在廣播發送和接收時,都增加上相應的permission,用于權限驗證;
3.發送廣播時,指定特定廣播接收器所在的包名,具體是通過intent.setPackage(packageName)指定在,這樣此廣播将隻會發送到此包中的App内與之相比對的有效廣播接收器中。
App應用内廣播可以了解成一種局部廣播的形式,廣播的發送者和接收者都同屬于一個App。實際的業務需求中,App應用内廣播确實可能需要用到。同時,之是以使用應用内廣播時,而不是使用全局廣播的形式,更多的考慮到的是Android廣播機制中的安全性問題。
相比于全局廣播,App應用内廣播優勢展現在:
1.安全性更高;
2.更加高效。
為此,Android v4相容包中給出了封裝好的LocalBroadcastManager類,用于統一處理App應用内的廣播問題,使用方式上與通常的全局廣播幾乎相同,隻是注冊/取消注冊廣播接收器和發送廣播時将主調context變成了LocalBroadcastManager的單一執行個體。
- 代碼示例如下:
//執行個體化MyBroadcastReceiver
mBroadcastReceiver = new MyBroadcastReceiver();
//執行個體化IntentFilter
IntentFilter intentFilter = new IntentFilter();
//得到LocalBroadcastManager執行個體
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);
//設定接收廣播的類型
intentFilter.addAction(BROADCAST_ACTION);
//動态注冊
localBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);
//取消注冊
localBroadcastManager.unregisterReceiver(mBroadcastReceiver);
三、廣播接收者(BroadCastReceiver)的兩種注冊方式
1).常駐型廣播(靜态注冊)
常駐型廣播,這個廣播接收者會在程式運作的整個過程中一直存在,不會被登出掉,當程式被殺掉後不會再接收到廣播了。它的注冊方式就是在你應用程式的AndroidManifast.xml 中進行注冊,這種注冊方式通常又被稱作靜态注冊。這種方式可以了解為通過清單檔案注冊的廣播是交給作業系統去處理的。在Manifest.xml中注冊廣播,是一種比較推薦的方法,因為它不需要手動登出廣播(如果廣播未登出,程式退出時可能會出錯)。
例如:下邊是注冊的一些系統廣播接收者
首先寫一個類繼承自BroadCastReceiver。
package com.example.mybroadcastreceiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
/**
* 這是一個擷取系統的廣播。是一個接收撥打電話的廣播
* 在配置檔案中配置了廣播接收的過濾意圖來實作注冊
* 這個廣播是隻有程式在運作就一直處于接收狀态,當程式被殺死後就無法再接收到廣播了
*
* <!-- 系統廣播,接收打電話的廣播 ,這個需要配置權限 -->
<!-- <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" /> -->
<receiver android:name="com.example.mybroadcastreceiver.OutCallReceiver" >
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
* @author Administrator
*
*/
public class OutCallReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
/**
* 這裡是接收到廣播後需要進行的操作都放在這裡
*/
System.out.println("接收到打電話的廣播了,可以在此做相應的操作");
Toast.makeText(context, "接收到打電話的廣播了,可以在此做相應的操作", 1).show();
}
}
然後在清單檔案中進行靜态的注冊配置。這樣就完成了對接收撥打電話廣播的注冊,在整個程式運作的過程中,隻要手機撥打電話了都能接收到這個廣播,并會執行onReceive中的代碼。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.mybroadcastreceiver"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<!-- 這裡将進入口的activity注釋掉就會導緻裝完app後不會顯示圖示和界面,但是廣播是能夠接收到。很流氓。 -->
<!-- 4.0以後就不會出現這種情況,必須啟動一次頁面後才能完成廣播的注冊。如果想實作不啟動頁面運作廣播,可以使用Service -->
<activity
android:name="com.example.mybroadcastreceiver.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- 系統廣播,接收打電話的廣播 ,這個需要配置權限 -->
<!-- <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" /> -->
<receiver android:name="com.example.mybroadcastreceiver.OutCallReceiver" >
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
<!-- 系統廣播,接收收到短信的廣播,這個需要配置權限 -->
<!-- <uses-permission android:name="android.permission.RECEIVE_SMS"/> -->
<receiver android:name="com.example.mybroadcastreceiver.SmSReceiver">
<intent-filter >
<!-- 4.0以後不提示了,需要自己手動輸入-->
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
<!-- 系統廣播,接收收到開機的廣播,這個需要配置權限 -->
<!-- <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> -->
<receiver android:name="com.example.mybroadcastreceiver.BootReceiver">
<intent-filter >
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
<!-- 系統廣播,當有應用被安裝、解除安裝、替換時 收到的廣播-->
<receiver android:name="com.example.mybroadcastreceiver.AppStatusReceiver">
<intent-filter >
<!--這個不是安裝,安裝時added <action android:name="android.intent.action.PACKAGE_INSTALL"/> -->
<action android:name="android.intent.action.PACKAGE_ADDED"/>
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
<action android:name="android.intent.action.PACKAGE_REPLACED"/>
<data android:scheme="package"/>
</intent-filter>
</receiver>
</application>
</manifest>
注意:BroadcastReceiver作為内部類時,如要通過靜态注冊的方式在清單檔案中注冊,必須要聲明為public static,否則會報錯:
沒有public報錯:java.lang.RuntimeException: Unable to instantiate receiver com.example.multibroadcastreceiver.MainActivity$ThirdBroadCast: java.lang.IllegalAccessException: access to class not allowed
沒有static報錯:java.lang.InstantiationException: can't instantiate class com.taodian.evacuation.fragment.AlarmFragment$MessageReceiver; no empty constructor
- 在
檔案中通過AndroidManifest.xml
進行注冊<receiver>
- 規則及執行個體說明:
<receiver
//BroadcastReceiver子類的類名
android:name="string"
//是否使用該BroadcastReceiver
android:enabled=["true" | "false"]
//此broadcastReceiver能否接收其他App的發出的廣播
//其預設值是由receiver中有無intent-filter決定的,如果有intent-filter,預設值為true,否則為false
android:exported=["true" | "false"]
android:icon="drawable resource"
android:label="string resource"
//具有相應權限的廣播發送方發送的廣播才能被此broadcastReceiver所接收
android:permission="string"
//broadcastReceiver運作所處的程序。
//預設為app的程序,可以指定獨立的程序
//Android四大基本元件都可以通過此屬性指定自己的獨立程序
android:process="string">
//指定此廣播接收器将用于接收特定的廣播類型
//本例中給出的時系統開機後自身發出的廣播
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
以上述靜态方法注冊的
MyBroadcastReceiver
,在
app
首次啟動時,系統或自動執行個體化
MyBroadcastReceiver
,并注冊到系統中。
2).非常駐型廣播(動态注冊)
非常駐型廣播,是通過代碼注冊廣播接收者的一種形式。代碼注冊時可以将廣播接收者作為一個内部類寫在Activity中,也可以重新寫一個類繼承自BroadCastReceiver,需要用代碼注冊(注冊廣播可以寫在任意的地方,隻有注冊的廣播接收者才能收到對應的廣播),比如在 Activity 中的 onCreate 或者 onResume 中注冊廣播接收者,在 onDestory 中登出廣播接收者。這樣你的廣播接收者就一個非常駐型的了,這種注冊方式也叫動态注冊。這種方式可以了解為通過代碼注冊的廣播是和注冊者關聯在一起的。
下面是在Activity中注冊和登出廣播接收者:
package com.example.mybroadcastreceiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.ResultReceiver;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends ActionBarActivity {
private static final String MY_BROADCAST_ACTION = "com.example.mybroadcastreceiver.my_broadcast_action";
private FirstBroadCast firstBroadCast;
private TwiceBroadCast twiceBroadCast;
private ThirdBroadCast thirdBroadCast;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
firstBroadCast = new FirstBroadCast();
IntentFilter filter1 = new IntentFilter();
filter1.addAction(MY_BROADCAST_ACTION);
filter1.setPriority(1000);
registerReceiver(firstBroadCast, filter1);
twiceBroadCast = new TwiceBroadCast();
IntentFilter filter2 = new IntentFilter();
filter2.addAction(MY_BROADCAST_ACTION);
filter1.setPriority(5);
registerReceiver(twiceBroadCast, filter2);
thirdBroadCast = new ThirdBroadCast();
IntentFilter filter3 = new IntentFilter();
filter3.addAction(MY_BROADCAST_ACTION);
filter1.setPriority(6);
registerReceiver(thirdBroadCast, filter3);
// finish();
}
public void sendBroadCast(View v){
//這裡建立電台來發送廣播,需要一個intent就行了
Intent intent = new Intent();
//給廣播設定一個action,友善廣播接收者接收相應的廣播
intent.setAction(MY_BROADCAST_ACTION);
intent.putExtra("data", "這裡是來自自定義電台發送的廣播");
// sendBroadcast(intent);//這裡發送的是無序廣播
/*
* 有序廣播
* intent:你要發送的資料,包含資料和動作
* receiverPermission:權限,一般不用為null
* resultReceiver:最終接收者
* Handler:消息處理
* initialCode:初始化編碼1 - 1000
* initialData:初始化的資料
* initialExtras:額外的資料,一般不用
*/
sendOrderedBroadcast(intent, null, null, null, 1, "10000", null);
}
//這個廣播接收者可用寫在任意的類中,甚至可用寫在别的app中。也能接收到對應電台發送的廣播,隻要action對應
//這些廣播可以通過在清單檔案中注冊,也可以手動的通過registerReceiver方法注冊
class FirstBroadCast extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (MY_BROADCAST_ACTION.equals(action)) {
String data = intent.getStringExtra("data");
Toast.makeText(context,
"FirstBroadCast接收到廣播了,接收的廣播的資料是:" + data, 1).show();
System.out.println("FirstBroadCast接收到廣播了,接收的廣播的資料是:" + data);
}
}
}
class TwiceBroadCast extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (MY_BROADCAST_ACTION.equals(action)) {
String data = intent.getStringExtra("data");
Toast.makeText(context,
"TwiceBroadCast接收到廣播了,接收的廣播的資料是:" + data, 1).show();
System.out.println("TwiceBroadCast接收到廣播了,接收的廣播的資料是:" + data);
}
}
}
class ThirdBroadCast extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (MY_BROADCAST_ACTION.equals(action)) {
String data = intent.getStringExtra("data");
Toast.makeText(context,
"ThirdBroadCast接收到廣播了,接收的廣播的資料是:" + data, 1).show();
System.out.println("ThirdBroadCast接收到廣播了,接收的廣播的資料是:" + data);
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if(firstBroadCast != null){
unregisterReceiver(firstBroadCast);
}
if(twiceBroadCast != null){
unregisterReceiver(twiceBroadCast);
}
if(thirdBroadCast != null){
unregisterReceiver(thirdBroadCast);
}
}
}
- 在代碼中調用
,Context.registerReceiver()
- 典型寫法示例如下:
public class MainActivity extends AppCompatActivity {
public static final String BROADCAST_ACTION = "com.example.whd_alive";
private BroadcastReceiver mBroadcastReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//執行個體化MyBroadcastReceiver
mBroadcastReceiver = new MyBroadcastReceiver();
//執行個體化IntentFilter
IntentFilter intentFilter = new IntentFilter();
//設定接收廣播的類型
intentFilter.addAction(BROADCAST_ACTION);
//動态注冊
registerReceiver(mBroadcastReceiver, intentFilter);
}
//銷毀廣播
//當此Activity執行個體化時,會動态将MyBroadcastReceiver注冊到系統中
//當此Activity銷毀時,動态注冊的MyBroadcastReceiver将不再接收到相應的廣播
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mBroadcastReceiver);
}
}
實作流程
- 廣播接收者BroadcastReceiver通過Binder機制向AMS(Activity Manager Service)進行注冊;
- 廣播發送者通過binder機制向AMS發送廣播;
- AMS查找符合相應條件(IntentFilter/Permission等)的BroadcastReceiver
- AMS将廣播發送到上述符合條件的BroadcastReceiver相應的消息循環隊列中
- BroadcastReceiver通過消息循環執行拿到此廣播,回調BroadcastReceiver中的onReceive()方法。
四.不同注冊方式的廣播接收器回調onReceive(context, intent)中的context具體類型
1).對于靜态注冊的ContextReceiver,回調onReceive(context, intent)中的context具體指的是ReceiverRestrictedContext;
2).對于全局廣播的動态注冊的ContextReceiver,回調onReceive(context, intent)中的context具體指的是Activity Context;
3).對于通過LocalBroadcastManager動态注冊的ContextReceiver,回調onReceive(context, intent)中的context具體指的是Application Context。
注:對于LocalBroadcastManager方式發送的應用内廣播,隻能通過LocalBroadcastManager動态注冊的ContextReceiver才有可能接收到(靜态注冊或其他方式動态注冊的ContextReceiver是接收不到的)。
五、不同Android API版本中廣播機制相關API重要變遷
1).Android5.0/API level 21開始粘滞廣播和有序粘滞廣播過期,以後不再建議使用;
2).”靜态注冊的廣播接收器即使app已經退出,主要有相應的廣播發出,依然可以接收到,但此種描述自Android 3.1開始有可能不再成立“
Android 3.1開始系統在Intent與廣播相關的flag增加了參數,分别是FLAG_INCLUDE_STOPPED_PACKAGES和FLAG_EXCLUDE_STOPPED_PACKAGES。
FLAG_INCLUDE_STOPPED_PACKAGES:包含已經停止的包(停止:即包所在的程序已經退出)
FLAG_EXCLUDE_STOPPED_PACKAGES:不包含已經停止的包
主要原因如下:
自Android3.1開始,系統本身則增加了對所有app目前是否處于運作狀态的跟蹤。在發送廣播時,不管是什麼廣播類型,系統預設直接增加了值為FLAG_EXCLUDE_STOPPED_PACKAGES的flag,導緻即使是靜态注冊的廣播接收器,對于其所在程序已經退出的app,同樣無法接收到廣播。
詳情參加Android官方文檔:http://developer.android.com/about/versions/android-3.1.html#launchcontrols
由此,對于系統廣播,由于是系統内部直接發出,無法更改此intent flag值,是以,3.1開始對于靜态注冊的接收系統廣播的BroadcastReceiver,如果App程序已經退出,将不能接收到廣播。
但是對于自定義的廣播,可以通過複寫此flag為FLAG_INCLUDE_STOPPED_PACKAGES,使得靜态注冊的BroadcastReceiver,即使所在App程序已經退出,也能能接收到廣播,并會啟動應用程序,但此時的BroadcastReceiver是重新建立的。
1 Intent intent = new Intent();
2 intent.setAction(BROADCAST_ACTION);
3 intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
4 intent.putExtra("name", "qqyumidi");
5 sendBroadcast(intent);
注1:對于動态注冊類型的BroadcastReceiver,由于此注冊和取消注冊實在其他元件(如Activity)中進行,是以,不受此改變影響。
注2:在3.1以前,相信不少app可能通過靜态注冊方式監聽各種系統廣播,以此進行一些業務上的處理(如即時app已經退出,仍然能接收到,可以啟動service等..),3.1後,靜态注冊接受廣播方式的改變,将直接導緻此類方案不再可行。于是,通過将Service與App本身設定成不同的程序已經成為實作此類需求的可行替代方案。
六、Android 廣播的生命周期
一個廣播接收者有一個回調方法:void onReceive(Context curContext, Intent broadcastMsg)。當一個廣播消息到達接收者時,Android調用它的onReceive()方法并傳遞給它包含消息的Intent對象。廣播接收者被認為僅當它執行這個方法時是活躍的。當onReceive()傳回後,它是不活躍的。
有一個活躍的廣播接收者的程序是受保護的,不會被殺死。但是系統可以在任何時候殺死僅有不活躍元件的程序,當占用的記憶體别的程序需要時。
這帶來一個問題,當一個廣播消息的響應時費時的,是以應該在獨立的線程中做這些事,遠離使用者界面其它元件運作的主線程。如果onReceive()衍生線程然後傳回,整個程序,包括新的線程,被判定為不活躍的(除非程序中的其它應用程式元件是活躍的),将使它處于被殺的危機。解決這個問題的方法是onReceive()啟動一個服務,及時服務做這個工作,是以系統知道程序中有活躍的工作在做。
Broadcast Receive為廣播接收器,它和事件處理機制類似,隻不過事件的處理機制是程式元件級别的,廣播處理機制是系統級别的。
Broadcast Receiver用于接收并處理廣播通知(broadcast announcements)。多數的廣播是系統發起的,如地域變換、電量不足、來電來信等。程式也可以播放一個廣播。程式可以有任意數量的 broadcast receivers來響應它覺得重要的通知。broadcast receiver可以通過多種方式通知使用者:啟動activity、使用NotificationManager、開啟背景燈、振動裝置、播放聲音等,最典型的是在狀态欄顯示一個圖示,這樣使用者就可以點它打開看通知内容。
通常我們的某個應用或系統本身在某些事件(電池電量不足、來電來短信)來臨時會廣播一個Intent出去,我們可以利用注冊一個Broadcast Receiver來監聽到這些Intent并擷取Intent中的資料。
七、開發BroadcastReceiver的一些注意事項:
BroadcastReceiver的生命周期比較短,一些比較費時的操作不應該放在onReceiver裡完成。如果在onReceiver()的方法不能在10秒内執行完成,将會産生程式無響應也就是我們熟悉的ANR(Application not Response)。但是如果非得要在這裡面執行一些費時的操作我們可以在這個onReceiver去啟動一個Service來完成這樣的一個費時操作。
廣播接收者的對象隻有在回調onReceive()這個函數時有效,一旦從這個函數傳回,這個對象就被結束,不再激活。在onReceive()中,任何異步的操作都是不可行的。因為需要從onRecive()這個函數回來去處理異步的操作,但是這個廣播接收者不再被激活,系統将會在異步操作完成前結束程序。特别是在這裡面顯示對話框或者綁定service不行,但是可以用其他替代的方式,前者可以notificationManger,後者用startService()發送請求。
下邊是一個如何使用廣播的代碼案例位址,需要的可以下載下傳:
http://download.csdn.net/detail/oonullpointeralex/9064049
八、系統廣播清單
android.accounts.LOGIN_ACCOUNTS_CHANGED
android.accounts.action.ACCOUNT_REMOVED
android.app.action.ACTION_PASSWORD_CHANGED
android.app.action.ACTION_PASSWORD_EXPIRING
android.app.action.ACTION_PASSWORD_FAILED
android.app.action.ACTION_PASSWORD_SUCCEEDED
android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED
android.app.action.APP_BLOCK_STATE_CHANGED
android.app.action.DEVICE_ADMIN_DISABLED
android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED
android.app.action.DEVICE_ADMIN_ENABLED
android.app.action.DEVICE_OWNER_CHANGED
android.app.action.INTERRUPTION_FILTER_CHANGED
android.app.action.LOCK_TASK_ENTERING
android.app.action.LOCK_TASK_EXITING
android.app.action.NEXT_ALARM_CLOCK_CHANGED
android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED
android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED
android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED
android.app.action.NOTIFICATION_POLICY_CHANGED
android.app.action.PROFILE_OWNER_CHANGED
android.app.action.PROFILE_PROVISIONING_COMPLETE
android.app.action.SYSTEM_UPDATE_POLICY_CHANGED
android.appwidget.action.APPWIDGET_DELETED
android.appwidget.action.APPWIDGET_DISABLED
android.appwidget.action.APPWIDGET_ENABLED
android.appwidget.action.APPWIDGET_HOST_RESTORED
android.appwidget.action.APPWIDGET_RESTORED
android.appwidget.action.APPWIDGET_UPDATE
android.appwidget.action.APPWIDGET_UPDATE_OPTIONS
android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED
android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED
android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED
android.bluetooth.adapter.action.DISCOVERY_FINISHED
android.bluetooth.adapter.action.DISCOVERY_STARTED
android.bluetooth.adapter.action.LOCAL_NAME_CHANGED
android.bluetooth.adapter.action.SCAN_MODE_CHANGED
android.bluetooth.adapter.action.STATE_CHANGED
android.bluetooth.device.action.ACL_CONNECTED
android.bluetooth.device.action.ACL_DISCONNECTED
android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED
android.bluetooth.device.action.BOND_STATE_CHANGED
android.bluetooth.device.action.CLASS_CHANGED
android.bluetooth.device.action.FOUND
android.bluetooth.device.action.NAME_CHANGED
android.bluetooth.device.action.PAIRING_REQUEST
android.bluetooth.device.action.UUID
android.bluetooth.devicepicker.action.DEVICE_SELECTED
android.bluetooth.devicepicker.action.LAUNCH
android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT
android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED
android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED
android.bluetooth.hiddevice.profile.action.CONNECTION_STATE_CHANGED
android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED
android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED
android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED
android.content.pm.action.SESSION_COMMITTED
android.hardware.action.NEW_PICTURE
android.hardware.action.NEW_VIDEO
android.hardware.hdmi.action.OSD_MESSAGE
android.hardware.input.action.QUERY_KEYBOARD_LAYOUTS
android.hardware.usb.action.USB_ACCESSORY_ATTACHED
android.hardware.usb.action.USB_ACCESSORY_DETACHED
android.hardware.usb.action.USB_DEVICE_ATTACHED
android.hardware.usb.action.USB_DEVICE_DETACHED
android.intent.action.ACTION_POWER_CONNECTED
android.intent.action.ACTION_POWER_DISCONNECTED
android.intent.action.ACTION_SHUTDOWN
android.intent.action.AIRPLANE_MODE
android.intent.action.APPLICATION_RESTRICTIONS_CHANGED
android.intent.action.BATTERY_CHANGED
android.intent.action.BATTERY_LOW
android.intent.action.BATTERY_OKAY
android.intent.action.BOOT_COMPLETED
android.intent.action.CAMERA_BUTTON
android.intent.action.CLOSE_SYSTEM_DIALOGS
android.intent.action.CONFIGURATION_CHANGED
android.intent.action.CONTENT_CHANGED
android.intent.action.DATA_SMS_RECEIVED
android.intent.action.DATE_CHANGED
android.intent.action.DEVICE_STORAGE_LOW
android.intent.action.DEVICE_STORAGE_OK
android.intent.action.DOCK_EVENT
android.intent.action.DOWNLOAD_COMPLETE
android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED
android.intent.action.DREAMING_STARTED
android.intent.action.DREAMING_STOPPED
android.intent.action.DROPBOX_ENTRY_ADDED
android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE
android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE
android.intent.action.FACTORY_RESET
android.intent.action.FETCH_VOICEMAIL
android.intent.action.GTALK_CONNECTED
android.intent.action.GTALK_DISCONNECTED
android.intent.action.HEADSET_PLUG
android.intent.action.HEADSET_PLUG
android.intent.action.INPUT_METHOD_CHANGED
android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION
android.intent.action.LOCALE_CHANGED
android.intent.action.LOCKED_BOOT_COMPLETED
android.intent.action.MANAGE_PACKAGE_STORAGE
android.intent.action.MASTER_CLEAR_NOTIFICATION
android.intent.action.MEDIA_BAD_REMOVAL
android.intent.action.MEDIA_BUTTON
android.intent.action.MEDIA_CHECKING
android.intent.action.MEDIA_EJECT
android.intent.action.MEDIA_MOUNTED
android.intent.action.MEDIA_NOFS
android.intent.action.MEDIA_REMOVED
android.intent.action.MEDIA_SCANNER_FINISHED
android.intent.action.MEDIA_SCANNER_SCAN_FILE
android.intent.action.MEDIA_SCANNER_STARTED
android.intent.action.MEDIA_SHARED
android.intent.action.MEDIA_UNMOUNTABLE
android.intent.action.MEDIA_UNMOUNTED
android.intent.action.MY_PACKAGE_REPLACED
android.intent.action.NEW_OUTGOING_CALL
android.intent.action.NEW_VOICEMAIL
android.intent.action.PACKAGES_SUSPENDED
android.intent.action.PACKAGES_UNSUSPENDED
android.intent.action.PACKAGE_ADDED
android.intent.action.PACKAGE_CHANGED
android.intent.action.PACKAGE_DATA_CLEARED
android.intent.action.PACKAGE_FIRST_LAUNCH
android.intent.action.PACKAGE_FULLY_REMOVED
android.intent.action.PACKAGE_INSTALL
android.intent.action.PACKAGE_NEEDS_VERIFICATION
android.intent.action.PACKAGE_REMOVED
android.intent.action.PACKAGE_REPLACED
android.intent.action.PACKAGE_RESTARTED
android.intent.action.PACKAGE_VERIFIED
android.intent.action.PHONE_STATE
android.intent.action.PROVIDER_CHANGED
android.intent.action.PROXY_CHANGE
android.intent.action.QUERY_PACKAGE_RESTART
android.intent.action.REBOOT
android.intent.action.SCREEN_OFF
android.intent.action.SCREEN_ON
android.intent.action.SIM_STATE_CHANGED
android.intent.action.TIMEZONE_CHANGED
android.intent.action.TIME_SET
android.intent.action.TIME_TICK
android.intent.action.UID_REMOVED
android.intent.action.UMS_CONNECTED
android.intent.action.UMS_DISCONNECTED
android.intent.action.USER_PRESENT
android.intent.action.USER_UNLOCKED
android.intent.action.WALLPAPER_CHANGED
android.media.ACTION_SCO_AUDIO_STATE_UPDATED
android.media.AUDIO_BECOMING_NOISY
android.media.RINGER_MODE_CHANGED
android.media.SCO_AUDIO_STATE_CHANGED
android.media.VIBRATE_SETTING_CHANGED
android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION
android.media.action.HDMI_AUDIO_PLUG
android.media.action.MICROPHONE_MUTE_CHANGED
android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION
android.media.tv.action.CHANNEL_BROWSABLE_REQUESTED
android.media.tv.action.INITIALIZE_PROGRAMS
android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT
android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED
android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED
android.net.conn.BACKGROUND_DATA_SETTING_CHANGED
android.net.conn.CONNECTIVITY_CHANGE
android.net.conn.RESTRICT_BACKGROUND_CHANGED
android.net.nsd.STATE_CHANGED
android.net.scoring.SCORER_CHANGED
android.net.scoring.SCORE_NETWORKS
android.net.wifi.NETWORK_IDS_CHANGED
android.net.wifi.RSSI_CHANGED
android.net.wifi.SCAN_RESULTS
android.net.wifi.STATE_CHANGE
android.net.wifi.WIFI_STATE_CHANGED
android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED
android.net.wifi.p2p.CONNECTION_STATE_CHANGE
android.net.wifi.p2p.DISCOVERY_STATE_CHANGE
android.net.wifi.p2p.PEERS_CHANGED
android.net.wifi.p2p.STATE_CHANGED
android.net.wifi.p2p.THIS_DEVICE_CHANGED
android.net.wifi.rtt.action.WIFI_RTT_STATE_CHANGED
android.net.wifi.supplicant.CONNECTION_CHANGE
android.net.wifi.supplicant.STATE_CHANGE
android.nfc.action.ADAPTER_STATE_CHANGED
android.nfc.action.TRANSACTION_DETECTED
android.os.action.DEVICE_IDLE_MODE_CHANGED
android.os.action.POWER_SAVE_MODE_CHANGED
android.provider.Telephony.SECRET_CODE
android.provider.Telephony.SIM_FULL
android.provider.Telephony.SMS_CB_RECEIVED
android.provider.Telephony.SMS_DELIVER
android.provider.Telephony.SMS_RECEIVED
android.provider.Telephony.SMS_REJECTED
android.provider.Telephony.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED
android.provider.Telephony.WAP_PUSH_DELIVER
android.provider.Telephony.WAP_PUSH_RECEIVED
android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED
android.provider.action.EXTERNAL_PROVIDER_CHANGE
android.provider.action.SYNC_VOICEMAIL
android.security.STORAGE_CHANGED
android.security.action.KEYCHAIN_CHANGED
android.security.action.KEY_ACCESS_CHANGED
android.security.action.TRUST_STORE_CHANGED
android.speech.tts.TTS_QUEUE_PROCESSING_COMPLETED
android.speech.tts.engine.TTS_DATA_INSTALLED
android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED
android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED
android.telephony.action.REFRESH_SUBSCRIPTION_PLANS
android.telephony.action.SIM_APPLICATION_STATE_CHANGED
android.telephony.action.SIM_CARD_STATE_CHANGED
android.telephony.action.SIM_SLOT_STATUS_CHANGED
android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED
android.telephony.euicc.action.NOTIFY_CARRIER_SETUP
android.telephony.euicc.action.OTA_STATUS_CHANGED