Android開發之廣播機制

來源:互聯網
上載者:User
Android開發之廣播機制

/*

 *  Android開發之廣播機制

 *  北京Android俱樂部群:167839253

 * Created on: 2012-7-31

 * Author: blueeagle

 *  Email:liujiaxiang@gmail.com

 */

概述

在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>

至此,就完成了廣播和接收。他們位於不同的工程中。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.