http://blog.csdn.net/woaieillen/article/details/7373090
广播接收器:
广播接收者(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="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: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);
- }
- }
- 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"));
- }
- }
- }
- 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="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">
- <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组件。
public final void setResultData (String data)
Added in API level 1
Change the current result data of this broadcast; only works with broadcasts sent through Context.sendOrderedBroadcast. This is an arbitrary string whose interpretation is up to the broadcaster.
This method does not work with non-ordered broadcasts such as those sent with Context.sendBroadcast
Parameters
data The new result data; may be null.
See Also
setResult(int, String, Bundle)
public final void setResultExtras (Bundle extras)
Added in API level 1
Change the current result extras of this broadcast; only works with broadcasts sent through Context.sendOrderedBroadcast. This is a Bundle holding arbitrary data, whose interpretation is up to the broadcaster. Can be set to null. Calling this method completely replaces the current map (if any).
This method does not work with non-ordered broadcasts such as those sent with Context.sendBroadcast
Parameters
extras The new extra data map; may be null.
See Also
setResult(int, String, Bundle)