天天看點

android broadcast sendOrderedBroadcast

http://blog.csdn.net/zhongnan09/article/details/6552632

廣播接收器:

廣播接收者(broadcastreceiver)用于監聽系統事件或應用程式事件,通過調用context.sendbroadcast()、context.sendorderedbroadcast()可以向系統發送廣播意圖,通過廣播一個意圖(intent)可以被多個廣播接收者所接收,進而可以在不用修改原始的應用程式的情況下,讓你對事件作出反應。

       其中context.sendbroad()主要是用來廣播無序事件(也被稱為有序廣播 normal broadcast),即所有的接收者在理論上是同時接收到事件,同時執行的,對消息傳遞的效率而言這是比較好的做法。而context.sendorderedbroadcast()方法用來向系統廣播有序事件(ordered broadcast),接收者按照在manifest.xml檔案中設定的接收順序依次接收intent,順序執行的,接收的優先級可以在系統配置檔案中設定(聲明在intent-filter元素的android:priority屬性中,數值越大優先級别越高,其取值範圍為-1000到1000。當然也可以在調用intentfilter對象的setpriority()方法進行設定)。對于有序廣播而言,前面的接收者可以對接收到得廣播意圖(intent)進行處理,并将處理結果放置到廣播意圖中,然後傳遞給下一個接收者,當然前面的接收者有權終止廣播的進一步傳播。如果廣播被前面的接收者終止後,後面的接收器就再也無法接收到廣播了。

廣播接收器(broadcaset)運作的線程:

       無論對于有序廣播還是無序廣播,廣播接收器預設都是運作在主線程中的(main線程,即ui線程)。可以通過在程式中使用registerreceiver(receiver, filter, broadcastpermission, scheduler)方法中的最後一個參數指定要運作的廣播接收器的線程。也可以在manifest.xml檔案中設定(intent-filter标簽中設定android:process)。

無序廣播(normal broadcast)

       基本步驟:寫一個類繼承broadcastreceiver,并重寫onreceive方法,而後在androidmanifest.xml文中中進行配置,或者直接在代碼中注冊。

下面是一個廣播接收器的demo(用于發送和接收短信):

import android.content.broadcastreceiver;

import android.content.context;

import android.content.intent;

import android.os.bundle;

import android.telephony.smsmessage;

import android.util.log;

public class receivingsmsreceiver extends broadcastreceiver

{

    private static final string sms_received ="android.provider.telephony.sms_received";

    private static final string tag = "receivingsmsreceiver";

    @override

    public void onreceive(context

context, intent intent) {

       if (intent.getaction().equals(sms_received))

           bundle bundle = intent.getextras();

           if (bundle != null)

              object[] pdus = (object[]) bundle.get("pdus");

              smsmessage[] messages = new smsmessage[pdus.length];

              for (int i

= 0; i < pdus.length; i++)

                  messages[i] = smsmessage.createfrompdu((byte[]) pdus[i]);

              for (smsmessage message : messages) {

                  string msg = message.getmessagebody();

                  log.i(tag, msg);

                  string to = message.getoriginatingaddress();

                  log.i(tag, to);

              }

           }

       }

    }

}

在androidmanifest.xml檔案中的<application>節點裡對接收到短信的廣播intent進行注冊:

<receiver android:name=". receivingsmsreceiver">

<intent-filter>

<action android:name="android.provider.telephony.sms_received"/>

</intent-filter>

</receiver>

在androidmanifest.xml檔案中添加以下權限:

<uses-permission android:name="android.permission.receive_sms"/><!-- 接收短信權限 -->

該廣播接收器将首先得到本機收到的短信,可以對短信内容進行過濾。

在模拟器中運作該工程。

建立一個新的android工程,建立一個activity用來發送短信:

import android.app.activity;

import android.app.pendingintent;

import android.content.intentfilter;

import android.telephony.smsmanager;

import android.view.view;

import android.widget.button;

import android.widget.edittext;

import android.widget.toast;

public class smssender extends activity

    private static final string tag = "smssender";

    button send = null;

    edittext address = null;

    edittext content = null;

    private mservicereceiver mreceiver01, mreceiver02;

    private static string send_actioin = "sms_send_action";

    private static string delivered_action = "sms_delivered_action";

    protected void oncreate(bundle

savedinstancestate) {

       super.oncreate(savedinstancestate);

       setcontentview(r.layout.main);

       address = (edittext) findviewbyid(r.id.address);

       content = (edittext) findviewbyid(r.id.content);

       send = (button) findviewbyid(r.id.send);

       send.setonclicklistener(new view.onclicklistener()

           @override

           public void onclick(view

v) {

              // todo auto-generated method

stub

              string maddress = address.gettext().tostring().trim();

              string mcontent = content.gettext().tostring().trim();

              if ("".equals(maddress)

|| "".equals(mcontent)) {

                  toast.maketext(smssender.this, "發送位址為空或内容為空!",

                         toast.length_long).show();

                  return;

              smsmanager smsmanager = smsmanager.getdefault();

              try {

                  intent send_intent = new intent(send_actioin);

                  intent deliver_intent = new intent(delivered_action);

                  pendingintent msend = pendingintent.getbroadcast(

                         getapplicationcontext(), 0, send_intent, 0);

                  pendingintent mdeliver = pendingintent.getbroadcast(

                         getapplicationcontext(), 0, deliver_intent, 0);

                  smsmanager.sendtextmessage(maddress, null, mcontent, msend,

                         mdeliver);

              } catch (exception e) {

                  e.printstacktrace();

       });

    protected void onresume()

       // todo auto-generated method stub

       intentfilter mfilter01;

       mfilter01 = new intentfilter(send_actioin);

       mreceiver01 = new mservicereceiver();

       registerreceiver(mreceiver01, mfilter01);

       mfilter01 = new intentfilter(delivered_action);

       mreceiver02 = new mservicereceiver();

       registerreceiver(mreceiver02, mfilter01);

       super.onresume();

    protected void onpause()

       unregisterreceiver(mreceiver01);

       unregisterreceiver(mreceiver02);

       super.onpause();

    public class mservicereceiver extends broadcastreceiver

       @override

       public void onreceive(context

           // todo auto-generated method stub

           if (intent.getaction().equals(send_actioin))

                  switch (getresultcode()) {

                  case activity.result_ok:

                     break;

                  case smsmanager.result_error_generic_failure:

                  case smsmanager.result_error_radio_off:

                  case smsmanager.result_error_null_pdu:

                  }

                  e.getstacktrace();

           } else if (intent.getaction().equals(delivered_action))

界面布局:

<?xml version="1.0" encoding="utf-8"?>

<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical" android:layout_width="fill_parent"

    android:layout_height="fill_parent">

    <textview android:layout_width="fill_parent"

       android:layout_height="wrap_content" android:text="發送短信" />

    <textview android:text="收信人位址:" android:id="@+id/textview1"

       android:layout_width="wrap_content" android:layout_height="wrap_content"></textview>

    <edittext android:text="" android:layout_width="match_parent"

       android:id="@+id/address" android:layout_height="wrap_content"></edittext>

    <textview android:text="短信内容:" android:id="@+id/textview2"

       android:id="@+id/content" android:layout_height="wrap_content"></edittext>

    <button android:text="發送" android:id="@+id/send"

       android:layout_width="wrap_content" android:layout_height="wrap_content"></button>

</linearlayout>

在androidmanifest.xml檔案中增加對該activity的配置:

<activity android:name=".smssender" 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.send_sms"/><!—發送短信權限 -->

在另一個模拟器中運作該工程。

由于本文的重點内容并不是發送和接收短信,是以,對短信發送和接收的内容并沒有詳細解釋。如果對短信收發内容不熟悉的朋友,可以查閱相關文檔。

有序廣播:

接收器1:

public class broadcasttest2 extends broadcastreceiver

arg0, intent arg1) {

       system.out.println("運作線程:    " +

thread.currentthread().getid() + "   "

              + thread.currentthread().getname());

       system.out.println("廣播意圖的動作:  " +

arg1.getaction());

       bundle bundle = new bundle();

       bundle.putstring("test", "zhongnan");

       setresultextras(bundle);

接收器2:

public class broadcasttest1 extends broadcastreceiver

       bundle bundle = getresultextras(false);

       if (bundle == null)

           system.out.println("沒有得到上次傳遞的資料");

       } else {

           system.out.println("測試:  " +

bundle.getstring("test"));

主activity,用來發送廣播:

public class mainactivity extends activity

    /** called when the activity is first created. */

    public void oncreate(bundle

       this.sendorderedbroadcast(new intent(

              "android.provier.zhongnan.broadcast"), null);

androidmanifest.xml檔案:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.zhongnan.bc" android:versioncode="1" android:versionname="1.0">

    <uses-sdk android:minsdkversion="8" />

    <application android:icon="@drawable/icon" android:label="@string/app_name">

       <activity android:name=".mainactivity" android:label="@string/app_name">

       <receiver android:name=".broadcasttest1">

              <action android:name="android.provier.zhongnan.broadcast"

                  android:priority="400" />

       </receiver>

       <receiver android:name=".broadcasttest2">

                  android:priority="500" />

    </application>

</manifest>

在mainactivity中發送有序廣播context.sendorderedbroadcast(),由于broadcasttest2中設定的接收優先級比較高,是以在broadcasttest2中将首先接收到廣播意圖,可以在broadcasttest2中對該廣播意圖進行處理,可以加入處理後的資料給後面的接收器使用,也可以在該接收器中終止廣播的進一步傳遞。在廣播中加入處理後的資料使用setresultextras(bundle

bundle)方法,關于bundle類,類似于hashmap,不熟悉的朋友可以參考文檔,或者檢視我的另一篇部落格。在後面的接收器中使用getresultextras(boolean

flag)接收前面的接收器存放的資料,其中的boolean參數含義為:true代表如果前面的接收器沒有存放資料,則自動建立一個空的bundle對象,false則表示如果前面的接收器如果沒有存放任何資料則傳回null。

廣播接收器中權限的定義:

    在發送廣播時,無論是無序廣播(normal broadcast)還是有序廣播(ordered broadcast)都有類似的方法:sendbroadcast (intent intent, string receiverpermission), sendorderedbroadcast (intent intent, string receiverpermission)。其中第二個參數是設定權限,即接收器必須具有相應的權限才能正常接收到廣播。

下面是在上述例子的基礎上添加自定義權限的例子:

         接收器1:

              "android.provier.zhongnan.broadcast"), "xzq.zhongnan.test");

代碼中與上述例子最大的差别在于mainactivity中發送廣播的代碼: this.sendorderedbroadcast(new intent(

              "android.provier.zhongnan.broadcast"), "xzq.zhongnan.test")增加了自定義的一個權限。

在androidmanifest檔案中配置自定義的權限:

    <permission android:protectionlevel="normal" android:name="xzq.zhongnan.test"></permission>

關于如何在工程中自定義權限請查閱相關文檔,或檢視我的另一篇部落格。

相應的,接收器中必須設定接收權限:

<uses-permission android:name="xzq.zhongnan.test"></uses-permission>

這樣,接收器就可以正确接收到廣播了。

另外,上述程式已講到,broadcastreceiver是允許在主線程中的,是以,在onreceive方法中執行的代碼,運作時間不能超過5s,否則将報出程式沒有相應的異常,如果要執行的代碼運作的時間比較長,可以使用service元件。

繼續閱讀