Android開發之廣播機制
Android開發之廣播機制
概述
在Android中,有一些操作完成以后,會發送廣播,比如說發出一條短信,或打出一個電話,如果某個程序接收了這個廣播,就會做相應的處理。這個廣播跟我們傳統意義中的電臺廣播有些相似之處。之所以叫做廣播,就是因為它只負責“說”而不管你“聽不聽”,也就是不管你接收方如何處理。另外,廣播可以被不只一個應用程序所接收,當然也可能不被任何應用程序所接收。
什么是Broadcast Receiver
BroadcastReceiver是Android應用程序中的第三個組件。Broadcast Reciver和事件處理機制類似,不同的是事件處理機制是應用程序組件級別的,比如一個按鈕的OnClickListener事件,只能夠在一個應用程序中處理。而廣播事件處理機制是系統級別的,不同的應用程序都可以處理廣播事件。
如何使用Broadcast Receiver
可以通過構建Intent對象,然后調用sendBroadcast()方法將廣播發出。事件的接受是通過一個繼承自BroadcastReceiver的類來實現的。繼承后重寫onReceiver()方法,在該方法中響應事件。當然不能忘記在AndroidManifest.xml文件中注冊BroadcastReceiver。
一般繼承自BroadcastReceiver的類,是我們根據自己的需求所自定義的。這個自定義的類的作用,就是用來處理android當中所發出的廣播事件。也就是說,Android操作系統中發出的廣播,由BroadcastReceiver這個類來接收。接收到以后,就會調用這個類中的onReceive()方法來進行處理。那么,在Android系統中,有很多的廣播,如何才能確定,一個receiver負責接收什么類型的廣播呢?對了。這就是要去書寫AndroidManifest.xml文件。我們需要在AndroidManifest.xml里進行注冊,將receiver注冊到應用程序中。這個receiver應該接收什么類型的事件是由Intent-filter來決定的。
對于onReceive方法,一旦方法返回。系統就會認為對象已經被完成。從而不再是活動狀態。
按照上述說明。簡單的看一個例子,代碼如下:
public class BroadcastReceiverTest extends Activity {
private Button myButton;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myButton = (Button)findViewById(R.id.myButton);
myButton.setOnClickListener(newButton.OnClickListener(){
@Override
public void onClick(View v) {
Intent myIntent = new Intent();
myIntent.setAction(myIntent.ACTION_EDIT);
BroadcastReceiverTest.this.sendBroadcast(myIntent);//發送廣播
}
});
}
}需要編寫BroadcastReceiver類,代碼如下:
public class ReceiverTest extends BroadcastReceiver {
public ReceiverTest(){
System.out.println("ReceiverTest");
}
@Override
public void onReceive(Context arg0, Intent arg1) {
System.out.println("onReceive");
}
}
在AndroidManifest.xml中注冊的代碼如下:
<receiver
android:label="@string/app_name"
android:name=".ReceiverTest" >
<intent-filter >
<action android:name="android.intent.action.EDIT" />
</intent-filter>
</receiver>
編譯完成之后,我們在控制臺會得到如圖所示的結果:

如果連續按兩次按鈕,則會出現兩次。如圖所示:

在上面的例子中,Intent的Action類型為ACTION_EDIT,而在AndroidManifest.xml中注冊的receiver類型也是edit,<action android:name="android.intent.action.EDIT"/>
,這就表明這兩個Action進行了匹配。即執行了sendBroadcast方法之后,類型為edit的receiver就可以進行接收了。類型匹配成功的話,才會生成receiver的對象,從而調用onReceiver方法。上文中已經談到,每次接收廣播都會生成一個新的receiver對象。在處理完畢之后,這個對象就不會再被使用了。
注冊Broadcast Receiver的方法
BroadcastReceiver能夠監聽被廣播出來的對象,一般是會用Intent來進行廣播。那么,達到能夠監聽的目的,則BroadcastReceiver必須進行注冊。注冊方法有兩種:
在AndroidManifest.xml文件中進行注冊:
這里面需要注意一點的是,如果我在AndroidManifest.xml文件中進行注冊BroadcastReceiver的話,無論這個BroadcastReceiver所在的應用程序是運行狀態還是關閉狀態,這個BroadcastReceiver都是活動的,都可以接收到廣播的事件。例如,短信息的接收,電池耗電量的顯示等應用程序。我們在待機狀態時需要監聽這些狀態,但是我們不可能一直打開應用程序。
在應用程序的代碼中進行注冊:
當我們需要更新Activity里面的控件的狀態的時候,則需要在應用程序的代碼中進行注冊,這個時候我們如果在AndroidManifest.xml中注冊的話就不太合適了。因為只有我們在Activity能看到的時候才進行更新,而Activity看不見的時候,這個BroadcastReceiver就應該關閉。否則會浪費各種資源。因此,這個時候就需要在應用程序的代碼中進行注冊。在Activity啟動以后注冊BroadcastReceiver,在Activity不可見后取消注冊。
注冊的代碼很簡單就是registerReceiver(receiver,filter);
相應的,取消注冊的代碼為unregisterReciver(receiver);
參數receiver表示一個BroadcastReceiver對象( TheBroadcastReceiver to handle the broadcast.);filter表示一個Intent-filter對象( Selectsthe Intent broadcasts to be received.),與我們在AndroidManifest.xml 文件中所使用的Intent-filter標簽的作用是一樣的。后面會討論到如何創建一個Intent-filter對象。
下面用手機接收信息這個例子來說明。對應代碼如下:
public class BroadcastReceiverTest extends Activity {
private Button myRegisterbtn;
private Button myUnregisterbtn;
private SMSReceiver myMessageReceiver;
private static final String SMS_ACTION = "android.provider.Telephony.SMS_RECEIVED";
private static final String EDIT_ACTION = "android.intent.action.EDIT";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myRegisterbtn = (Button)findViewById(R.id.registerbtn);
myUnregisterbtn = (Button)findViewById(R.id.unregisterbtn);
myRegisterbtn.setOnClickListener(newmyRegisterListener());
myUnregisterbtn.setOnClickListener(newmyUnregisterListener());
}
class myRegisterListener implements OnClickListener{
@Override
public void onClick(View v) {
myMessageReceiver = new SMSReceiver();
//生成一個BroadReceiver對象
IntentFilter myFilter = new IntentFilter();
//生成一個IntentFilter對象
myFilter.addAction(SMS_ACTION);
//為IntentFilter添加一個Action
BroadcastReceiverTest.this.registerReceiver(myMessageReceiver, myFilter);
}
//整個操作完成了BroadcastReceiver的注冊。
}
class myUnregisterListener implements OnClickListener{
@Override
public void onClick(View v) {
BroadcastReceiverTest.this.unregisterReceiver(myMessageReceiver);
//將BroadcastReceiver對象在系統中解除注冊
}
}
}代碼很簡單,就是定義了兩個按鈕,其中一個是將BroadcastReceiver綁定到應用程序中,另一個則是解除BroadcastReceiver在應用程序中的綁定。相應的,我們還需要將接收器的類編寫出來,為了方便測試,我們只在接收器類里編寫一個打印輸出,代碼如下:
public class SMSReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
System.out.println("onReceivestart");
}
}
當然,我們這里是在應用程序中注冊的BroadcastReceiver,所以就不用在AndroidManifest.xml文件中再去注冊一次了。(讀者可以嘗試著仍然去AndroidManifest.xml文件中注冊,看看會發送什么現象。)運行程序,并且點擊注冊按鈕,然后利用DDMS來給模擬器發送一條短信。如圖所示:

當我們點擊完Send按鈕后,查看控制臺,則會發現“onReceive start”已經被打印出來了,如下圖所示:

這就意味著,接收器在過濾到發送信息這樣的事件后,接收到了廣播。至此,BroadcastReceiver的兩種注冊方式就講完了。
講完這兩種方式后,讀者可能會有一系列疑問。那就是,為什么我這個action是android.provider.Telephony.SMS_RECEIVED的時候,發送一個消息,對應的接收器就能夠接收到廣播,如果我的action不是這個,那么發送的廣播還會被接收嗎?又該怎么樣確定到底一個action對應什么操作?從而才能夠被廣播接收器接收到。Android系統中又多少內置的這種action?我們能不能自定義一個action?如果可以的話如何定義呢?
首先,我們來考察一下Android內置的Broadcast Actions。
Android內置的Broadcast Actions
在Android平臺中,內置了很多Action,用于幫助開發者監聽手機上所發生的各種事件。下面給出幾個內置的BroadcastAction的例子:
android.intent.action.BATTERY_CHANGED
充電狀態,或者電池的電量發生變化
android.intent.action.SCREEN_ON
屏幕已經被打開
android.intent.action.PACKAGE_REMOVED
設備上刪除了一個應用程序包
android.intent.action.TIME_TICK
當前時間已經變化(正常的時間流逝)
如果要查詢BroadcastAction的完整列表,可以在官方SDK的幫助文檔里面找到Intent類,在常量定義的解釋中,去找Broadcast Action開頭的信息就可以了。例如我們找到String類型的常量:ACTION_BATTERY_LOW,后面的解釋是以“Broadcast Action”開頭的。
String ACTION_BATTERY_LOW Broadcast Action: Indicates low batterycondition on the device.
一般來說,Android操作系統給我們提供的內置的Broadcast Action是夠用的,當然我們也可以進行自定義Broadcast的Action。
自定義Broadcast Action
自定義Broadcast Actions其實就是自定義一個字符串常量。然后將這個常量廣播出去,接收的地方再接收這個常量就可以了。下面利用代碼來說明自定義BroadcastAction,同時,這里還將BroadcastReceiver和負責廣播的工程分開成兩個工程來說明,對于不同工程之間的廣播接收的處理方式。代碼如下:
public class MyBroadcast extends Activity {
public static final String NEW_BROADCAST = "com.todd.NEW_BROADCAST";
/* 這個靜態常量字符串可以自己隨便定義,代表自定義的action*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button mybutton =(Button)findViewById(R.id.mybutton);
mybutton.setOnClickListener(newButton.OnClickListener() {
public void onClick(View v) {
Intent myIntent = new Intent(NEW_BROADCAST);
myIntent.putExtra("MSG", "地瓜地瓜,我是土豆!");
myIntent.setAction(NEW_BROADCAST);
sendBroadcast(myIntent);
}
});
}
}XML文件中只需要定義一個按鈕
<Button
android:id="@+id/mybutton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="發送廣播"
/>
然后再建立一個工程,作為接收的工程,這個工程負責接收廣播工程廣播出來的數據。代碼如下:
public class MyReceiver extends BroadcastReceiver {
/** Calledwhen the activity is first created. */
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generatedmethod stub
String message = intent.getExtras().getString("MSG");
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
System.out.println(message);
}
}
到這里還不算完。需要有一個注冊的過程。注冊的過程,就是讓接收工程知道我要接收來自哪一個Intent的數據。
在Androidmanifest.xml中注冊如下:
<receiver android:name=".MyReceiver">
<intent-filter>
<action android:name="com.todd.NEW_BROADCAST" />
</intent-filter>
</receiver>
這樣就把"com.todd.NEW_BROADCAST"動作注冊到了接收工程中。如此,接收工程完畢。
但是這樣就結束了嗎?還沒有。如果此時編譯后,廣播工程沒有任何問題,但是接收工程會出錯,classcast的錯誤。這是因為,我們在編譯接收工程的時候,沒有給接收工程一個Activity用于顯示接收的信息。因此,我們需要定義一個Activity.代碼如下:
public class IntentRes extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
當然,在相應的AndroidManifest.xml文件中要修改,寫為:
<activity android:name=".IntentRes"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
至此,就完成了廣播和接收。他們位于不同的工程中。
轉自:http://blog.csdn.net/redoffice/article/details/7848430