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