340
技術社區[雲棲]
android broadcast sendOrderedBroadcast
https://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.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
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";
@Override
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();
}
}
});
}
@Override
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();
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
unregisterReceiver(mReceiver01);
unregisterReceiver(mReceiver02);
super.onPause();
}
public class mServiceReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
if (intent.getAction().equals(SEND_ACTIOIN)) {
try {
switch (getResultCode()) {
case Activity.RESULT_OK:
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:
break;
case SmsManager.RESULT_ERROR_NULL_PDU:
break;
}
} catch (Exception e) {
e.getStackTrace();
}
} else if (intent.getAction().equals(DELIVERED_ACTION)) {
try {
switch (getResultCode()) {
case Activity.RESULT_OK:
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:
break;
case SmsManager.RESULT_ERROR_NULL_PDU:
break;
}
} catch (Exception e) {
e.getStackTrace();
}
}
}
}
}
界麵布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://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:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<EditText android:text="" android:layout_width="match_parent"
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>
在AndroidManifest.xml文件中添加以下權限:
<uses-permission android:name="android.permission.SEND_SMS"/><!—發送短信權限 -->
在另一個模擬器中運行該工程。
由於本文的重點內容並不是發送和接收短信,所以,對短信發送和接收的內容並沒有詳細解釋。如果對短信收發內容不熟悉的朋友,可以查閱相關文檔。
有序廣播:
接收器1:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
public class BroadcastTest2 extends BroadcastReceiver {
@Override
public void onReceive(Context 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:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
public class BroadcastTest1 extends BroadcastReceiver {
@Override
public void onReceive(Context arg0, Intent arg1) {
System.out.println("運行線程: " + Thread.currentThread().getId() + " "
+ Thread.currentThread().getName());
System.out.println("廣播意圖的動作: " + arg1.getAction());
Bundle bundle = getResultExtras(false);
if (bundle == null) {
System.out.println("沒有得到上次傳遞的數據");
} else {
System.out.println("測試: " + bundle.getString("test"));
}
}
}
主Activity,用來發送廣播:
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
public class MainActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
this.sendOrderedBroadcast(new Intent(
"android.provier.zhongnan.broadcast"), null);
}
}
AndroidManifest.xml文件:
<manifest xmlns:android="https://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">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".BroadcastTest1">
<intent-filter>
<action android:name="android.provier.zhongnan.broadcast"
android:priority="400" />
</intent-filter>
</receiver>
<receiver android:name=".BroadcastTest2">
<intent-filter>
<action android:name="android.provier.zhongnan.broadcast"
android:priority="500" />
</intent-filter>
</receiver>
</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:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
public class BroadcastTest2 extends BroadcastReceiver {
@Override
public void onReceive(Context 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:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
public class BroadcastTest1 extends BroadcastReceiver {
@Override
public void onReceive(Context arg0, Intent arg1) {
System.out.println("運行線程: " + Thread.currentThread().getId() + " "
+ Thread.currentThread().getName());
System.out.println("廣播意圖的動作: " + arg1.getAction());
Bundle bundle = getResultExtras(false);
if (bundle == null) {
System.out.println("沒有得到上次傳遞的數據");
} else {
System.out.println("測試: " + bundle.getString("test"));
}
}
}
主Activity,用來發送廣播:
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
public class MainActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
this.sendOrderedBroadcast(new Intent(
"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組件。
最後更新:2017-04-03 12:53:54