Android開發之廣播機制

openkk 12年前發布 | 60K 次閱讀 Android 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>

編譯完成之后,我們在控制臺會得到如圖所示的結果:

Android開發之廣播機制

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

Android開發之廣播機制

 

在上面的例子中,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來給模擬器發送一條短信。如圖所示:

Android開發之廣播機制

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

Android開發之廣播機制

這就意味著,接收器在過濾到發送信息這樣的事件后,接收到了廣播。至此,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

 本文由用戶 openkk 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!