前言:慢慢来吧!
今天在项目中遇到一个问题,动态注册广播时每次重启一个广播都会重新创建一个对象,继而随之销毁。超过10秒内奔溃,原来官方文档上说时间不能超过10秒,所以由于自己太菜,把BroadcastReceiver总结了一下:
BroadcastReceiver,顾名思义就是“广播接收者”的意思,它是Android四大基本组件之一,这种组件本质上是一种全局的监听器,用于监听系统全局的广播消息。它可以接收来自系统和应用的的广播。
由于BroadcastReceiver是一种全局的监听器,因此它可以非常方便地实现系统不同组件之间的通信。比如Activity与通过startService()方法启动的Service之间通信,就可以借助于BroadcastReceiver来实现。
BroadcastReceiver简介:
BroadcastReceiver用于接收程序(包括系统程序和一般应用)通过sendBroadcast()方法发出的Broadcast intents。
程序启动BroadcastReceiver的步骤(发出广播):
1) 创建需要启动BroadcastReceiver的Intent。
2) 调用Context的sendBroadcast
()或sendOrderedBroadcast
()方法来启动指定的BroadcastReceiver。其中sendBroadcast
发送的是普通广播,sendOrderedBroadcast发送的是有序广播。
当应用发出一个Broadcast Intent之后所匹配该Intent的组件都可能被启动。
创建BroadcastReceiver的步骤:
第一步:创建BroadcastReceiver的子类:
由于BroadcastReceiver本质上是一种监听器,所以创建BroadcastReceiver的方法也非常简单,只需要创建一个BroadcastReceiver的子类然后重写onReceive (Context context, Intentintent)方法即可。
具体代码如下:
1
2
3
4
5
6
7
8
9
10
|
public
class
MyBroadcastReceiver
extends
BroadcastReceiver {
@Override
public
void
onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String msg=intent.getExtras().get(
"msg"
).toString();
Toast.makeText(context,
"intent.getAction()"
+intent.getAction().toString(),
Toast.LENGTH_LONG).show();
System.out.println(
"msg:"
+msg);
}
}
|
第二步:注册BroadcastReceiver
一旦实现了BroadcastReceiver,接下就应该指定该BroadcastReceiver能匹配的Intent即注册BroadcastReceiver。注册BroadcastReceiver的方式有两种:
第一种是静态注册:这种方法是在配置AndroidManifest.xml配置文件中注册,通过这种方式注册的广播为常驻型广播,也就是说如果应用程序关闭了,有相应事件触发,程序还是会被系统自动调用运行。例如:
1
2
3
4
5
6
7
|
<!-- 在配置文件中注册BroadcastReceiver能够匹配的Intent -->
<receiver android:name=
"com.example.test.MyBroadcastReceiver"
>
<intent-filter>
</action>
<category android:name=
"android.intent.category.DEFAULT"
></category>
</intent-filter>
</receiver>
|
第二种是动态注册 :这种方法是通过代码在. Java 文件中进行注册。通过这种方式注册的广播为非常驻型广播,即它会跟随Activity的生命周期,所以在Activity结束前我们需要调用unregisterReceiver(receiver)方法移除它。例如:
1
2
3
4
5
6
|
//通过代码的方式动态注册MyBroadcastReceiver
MyBroadcastReceiver receiver=
new
MyBroadcastReceiver();
IntentFilter filter=
new
IntentFilter();
filter.addAction(
"android.intent.action.MyBroadcastReceiver"
);
//注册receiver
registerReceiver(receiver, filter);
|
注意: 如果我们在Activity中注册了BroadcastReceiver,当这个Activity销毁的时候要主动撤销注册否则会出现异常。方法如下:
1
2
3
4
5
6
7
|
@Override
protected
void
onDestroy() {
// TODO Auto-generated method stub
super
.onDestroy();
//当Activity销毁的时候取消注册BroadcastReceiver
unregisterReceiver(receiver);
}
|
BroadcastReceiver的生命周期:
BroadcastReceiver的生命周期,从对象调用它开始,到onReceiver方法执行完成之后结束。另外,每次广播被接收后会重新创建BroadcastReceiver对象,并在onReceiver方法中执行完就销毁,如果BroadcastReceiver的onReceiver方法中不能在10秒内执行完成,Android会出现ANR异常。所以不要在BroadcastReceiver的onReceiver方法中执行耗时的操作。
如果需要在BroadcastReceiver中执行耗时的操作,可以通过Intent启动Service来完成。但不能绑定Service。
特别是,您可能无法从一个BroadcastReceiver中显示一个对话框,或绑定到服务。对于前者,则应该使用NotificationManager的API。对于后者,你可以使用Context.startService()来启动一个Service。
广播的类型:
Broadcast的类型有两种:普通广播和有序广播。
Normal broadcasts(普通广播):Normal broadcasts是完全异步的可以同一时间被所有的接收者接收到。消息的传递效率比较高。但缺点是接收者不能讲接收的消息的处理信息传递给下一个接收者也不能停止消息的传播。
Ordered broadcasts(有序广播):Ordered broadcasts的接收者按照一定的优先级进行消息的接收。如:A,B,C的优先级依次降低,那么消息先传递给A,在传递给B,最后传递给C。优先级别声明在中,取值为[-1000,1000]数值越大优先级别越高。优先级也可通过filter.setPriority(10)方式设置。 另外Ordered broadcasts的接收者可以通过abortBroadcast()的方式取消广播的传播,也可以通过setResultData和setResultExtras方法将处理的结果存入到Broadcast中,传递给下一个接收者。然后,下一个接收者通过getResultData()和getResultExtras(true)接收高优先级的接收者存入的数据。
应用实例:
发送并接收普通和有序广播:
运行效果图:
实例代码:
MainActivity.java:发送广播:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
package
com.jph.broadcastreceiverdemo;
import
android.os.Bundle;
import
android.view.View;
import
android.view.View.OnClickListener;
import
android.widget.Button;
import
android.app.Activity;
import
android.content.Intent;
/**
* Describe:<br>
* <br>本实例有两个优先级别不同的广播接收器
* <br>通过发送普通广播,和有序广播来学习
* <br>BroadcastReceiver的原理
* <br>@author jph
* <br>@Date:2014.08.05
* */
public
class
MainActivity
extends
Activity {
MyBroadcastReceiver receiver;
Button btnSend,btnSend2;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnSend=(Button)findViewById(R.id.btnSend);
btnSend2=(Button)findViewById(R.id.btnSend2);
receiver=
new
MyBroadcastReceiver();
OnClickListener listener=
new
OnClickListener() {
@Override
public
void
onClick(View v) {
// TODO Auto-generated method stub
switch
(v.getId()) {
case
R.id.btnSend:
Intent intent=
new
Intent();
intent.setAction(
"android.intent.action.MyBroadcastReceiver"
);
intent.putExtra(
"msg"
,
"我在发送广播!这只是一个普通的广播,"
+
"你们无法通过abortBroadcast()的方式停止广播的传播,"
+
"也无法往Broadcast中存入数据因为它是异步的"
);
sendBroadcast(intent);
break
;
case
R.id.btnSend2:
Intent intent2=
new
Intent();
intent2.setAction(
"android.intent.action.MyBroadcastReceiver"
);
intent2.putExtra(
"msg"
,
"我在发送个有序的广播,"
+
"你们可以通过abortBroadcast()的方式停止广播的传播,"
+
"也可以往Broadcast中存入数据"
);
sendOrderedBroadcast(intent2,
null
);
break
;
default
:
break
;
}
}
};
btnSend.setOnClickListener(listener);
btnSend2.setOnClickListener(listener);
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
package
com.jph.broadcastreceiverdemo;
import
java.text.SimpleDateFormat;
import
java.util.Date;
import
android.content.BroadcastReceiver;
import
android.content.Context;
import
android.content.Intent;
import
android.widget.Toast;
/**
* Describe:<br>
* <br>@author jph
* <br>@Date:2014.08.05
* */
public
class
MyBroadcastReceiver
extends
BroadcastReceiver {
@Override
public
void
onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String msg=intent.getExtras().get(
"msg"
).toString();
setResultData(
"MyBroadcastReceiver接收到广播"
);
Toast.makeText(context,
"时间:"
+
new
SimpleDateFormat(
"yyyy-MM-dd hh.mm.ss"
).format(
new
Date())
+
"\nMyBroadcastReceiver收到Action名为:"
+intent.getAction().toString()
+
"的广播 \nComponent:"
+intent.getComponent()
+
"\nmsg:"
+msg,
Toast.LENGTH_LONG).show();
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
package
com.jph.broadcastreceiverdemo;
import
java.text.SimpleDateFormat;
import
java.util.Date;
import
android.content.BroadcastReceiver;
import
android.content.Context;
import
android.content.Intent;
import
android.widget.Toast;
/**
* Describe:<br>
* <br>@author jph
* <br>@Date:2014.08.05
* */
public
class
SecondBroadcastReceiver
extends
BroadcastReceiver {
@Override
public
void
onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String msg=intent.getExtras().get(
"msg"
).toString();
String result=getResultData();
Toast.makeText(context,
"时间:"
+
new
SimpleDateFormat(
"yyyy-MM-dd hh.mm.ss"
).format(
new
Date())
+
"\nSecondBroadcastReceiver收到Action名为:"
+intent.getAction().toString()
+
"的广播 \nComponent:"
+intent.getComponent()
+
"\nmsg:"
+msg+
"\n上一个接受者传来的reult:"
+result,
Toast.LENGTH_LONG).show();
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
<!--?xml version=
"1.0"
encoding=
"utf-8"
?-->
<manifest xmlns:android=
"http://schemas.android.com/apk/res/android"
package
=
"com.jph.broadcastreceiverdemo"
android:versioncode=
"1"
android:versionname=
"1.0"
>
<uses-sdk android:minsdkversion=
"8"
android:targetsdkversion=
"18"
>
<intent-filter>
<category android:name=
"android.intent.category.LAUNCHER"
>
</category></action></intent-filter>
</activity>
<!-- 在配置文件中注册MyBroadcastReceiver能够匹配的Intent -->
<receiver android:name=
"com.jph.broadcastreceiverdemo.MyBroadcastReceiver"
>
<intent-filter android:priority=
"200"
>
</action>
<category android:name=
"android.intent.category.DEFAULT"
></category>
</intent-filter>
</receiver>
<!-- 在配置文件中注册SecondBroadcastReceiver能够匹配的Intent -->
<receiver android:name=
"com.jph.broadcastreceiverdemo.SecondBroadcastReceiver"
>
<intent-filter android:priority=
"100"
>
</action>
<category android:name=
"android.intent.category.DEFAULT"
></category>
</intent-filter>
</receiver>
</application>
</uses-sdk></manifest>
|