Broadcast(广播)
Broadcast是一种广泛应用的、在应用之间传输信息的机制,Android中的广播与传统意义上的广播电台类似,一个广播可以有任意个接收者。广播机制是一个单行的发布——订阅模式,也就是现在常说的观察者模式。它的最大特点是发送方并不关心接收方是否收到数据,也不关心如何处理数据,通过这样的方式使得发送、接收达到完全解耦和。
- 广播的3个基本元素:发送广播的Broadcast、接收广播的BroadcastReceiver 、用于传输信息的Intent。
- 广播类型: 普通广播、有序广播、本地广播、Sticky广播
普通广播
普通广播完全是异步的,通过Context的sendBroadcast()函数来发送。
- 优点:消息传递的效率比较高,但所有的Receiver的执行顺序不确定。
- 缺点:接收者不能将处理结果传递给下一个接收者,并且无法终止广播Intent的传播,知道没有与之匹配的广播接收器为止。
- 用法 :发送广播的方法:sendBroadcast()。
示例代码:
/**
* Created by 泅渡者
* Created on 2017/9/26.
*/
public class CommonBroadcast extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String str = intent.getStringExtra("data");
KLog.d(str);
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent("com.bsoft.broadcasttest.CLOCK");
intent.putExtra("data", "Ding Ding 起床了!!!!");
sendBroadcast(intent);
}
}
注册
运行结果如下
D/CommonBroadcast.java: [ (CommonBroadcast.java:19)#onReceive ] Ding Ding 起床了!!!!
有序广播
- 优点:按优先级的不同,优先Receiver可对数据进行处理,并传给下一个Receiver,通过abortBroadcast可终止广播的传播 。
- 缺点:效率低
- 用法: 发送广播的方法:sendOrderedBroadcast(), 优先接收到Broadcast的Receiver可通过setResultExtras(Bundle)方法将处理结果存入Broadcast中,下一个Receiver 通过 Bundle bundle=getResultExtras(true)方法获取上一个 Receiver传来的数据。
我们在上面项目中新建OrderOBroadcast2、OrderOBroadcast1两个receiver,并进行注册。
OrderOBroadcast1.class
/**
* Created by 泅渡者
* Created on 2017/9/26.
*/
public class OrderOBroadcast1 extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle=getResultExtras(true);
KLog.d("我收到消息"+bundle.get("data")+"&&"+bundle.get("warning"));
}
}
OrderOBroadcast2.class
/**
* Created by 泅渡者
* Created on 2017/9/26.
*/
public class OrderOBroadcast2 extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle=intent.getExtras();
KLog.d("我收到消息"+bundle.get("data"));
bundle.putString("warning", "姐姐快起床");
setResultExtras(bundle);
//切断广播
// abortBroadcast();
}
}
注册
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
TextView tv_one;
TextView tv_two;
Intent intent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_one = (TextView) findViewById(R.id.tv_one);
tv_two = (TextView) findViewById(R.id.tv_two);
tv_one.setOnClickListener(this);
tv_two.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.tv_one:
intent = new Intent("com.bsoft.broadcasttest.CLOCK");
intent.putExtra("data", "Ding Ding 起床了!!!!");
sendBroadcast(intent);
break;
case R.id.tv_two:
intent = new Intent("com.bsoft.broadcasttest.ACTION");
Bundle bundle=new Bundle();
bundle.putString("data", "孩子们快起床");
intent.putExtras(bundle);
//有序广播
sendOrderedBroadcast(intent, null);
break;
}
}
}
代码简单相信都能看得懂,我们直接看运行结果:
/CommonBroadcast.java: [ (CommonBroadcast.java:19)#onReceive ] Ding Ding 起床了!!!!
D/OrderOBroadcast2.java: [ (OrderOBroadcast2.java:20)#onReceive ] 我收到消息孩子们快起床
D/OrderOBroadcast1.java: [ (OrderOBroadcast1.java:19)#onReceive ] 我收到消息孩子们快起床&&姐姐快起床
在这里我们看到事OrderOBroadcast2最先接收到广播的,这就是我们在注册时进行的设置。接着再来看看OrderOBroadcast1打印了两条数据,第一条是广播发出的消息,而第二条是OrderOBroadcast2发送来的。
本地广播
只在程序内部进行传递的广播,发送和接收都只在本程序有效。
本地广播是无法通过静态注册来实现的。因为静态注册是为了让程序未启动也能接收广播。本地广播是在本程序内进行传递,肯定是已经启动了,因此也完全不需要静态注册。
代码如下:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
TextView tv_one;
TextView tv_two;
TextView tv_three;
Intent intent;
//本地广播
private IntentFilter intentFilter;
private LocalReceiver localReceiver;
private LocalBroadcastManager localBroadcastManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_one = (TextView) findViewById(R.id.tv_one);
tv_two = (TextView) findViewById(R.id.tv_two);
tv_three = (TextView) findViewById(R.id.tv_three);
tv_one.setOnClickListener(this);
tv_two.setOnClickListener(this);
tv_three.setOnClickListener(this);
localBroadcastManager=LocalBroadcastManager.getInstance(this);
//新建intentFilter并给其action标签赋值。
intentFilter=new IntentFilter();
intentFilter.addAction("com.bsoft.broadcasttest.LOCAL_BROADCAST");
//创建广播接收器实例,并注册。将其接收器与action标签进行绑定。
localReceiver=new LocalReceiver();
localBroadcastManager.registerReceiver(localReceiver,intentFilter);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.tv_one:
intent = new Intent("com.bsoft.broadcasttest.CLOCK");
intent.putExtra("data", "Ding Ding 起床了!!!!");
sendBroadcast(intent);
break;
case R.id.tv_two:
intent = new Intent("com.bsoft.broadcasttest.ACTION");
Bundle bundle=new Bundle();
bundle.putString("data", "孩子们快起床");
intent.putExtras(bundle);
//有序广播
sendOrderedBroadcast(intent, null);
break;
case R.id.tv_three:
intent=new Intent("com.bsoft.broadcasttest.LOCAL_BROADCAST");
//发送本地广播。
localBroadcastManager.sendBroadcast(intent);
break;
}
}
@Override
public void onDestroy(){
super.onDestroy();
//取消注册调用的是unregisterReceiver()方法,并传入接收器实例。
localBroadcastManager.unregisterReceiver(localReceiver);
}
class LocalReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent){
Toast.makeText(context,"这是本地广播接收器",Toast.LENGTH_SHORT).show();
}
}
}
至此本地广播已经可以应用了。
Sticky广播
sticky广播通过Context.sendStickyBroadcast()函数来发送,用此函数发送的广播会一直滞留,当有匹配此广播的广播接收器被注册后,该广播接收器就会收到此条信息。使用此函数需要发送广播时,需要获得BROADCAST_STICKY权限
sendStickyBroadcast只保留最后一条广播,并且一直保留下去,这样即使已经有广播接收器处理了该广播,当再有匹配的广播接收器被注册时,此广播仍会被接收。如果你只想处理一遍该广播,可以通过removeStickyBroadcast()函数来实现。这里创建广播的过程和普通广播是一样的过程,这里就不过多介绍了
主要原因是在 android 5.0/api 21中deprecated,不再推荐使用,相应的还有粘性有序广播,同样已经deprecated
两种注册广播方式
- 常驻型广播(静态注册)
常驻型广播,当应用程序关闭了,如果有广播信息来,写的广播接收器同样的能接收到,它的注册方式就是在应用程序的AndroidManifast.xml 中进行注册。这种方式可以理解为通过清单文件注册的广播是交给操作系统去处理的
使用场景:开机自启动的实现
优点:不受应用生命周期的影响,常驻
缺点:常驻会耗费cpu、电量等资源
示例如下:
- 非常驻型广播(动态注册)
非常驻型广播,当应用程序结束了,广播自然就没有了,比如在 Activity 中的 onCreate 或者 onResume 中注册广播接收者,在 onDestory 中注销广播接收者。这样广播接收者就一个非常驻型的了,这种注册方式也叫动态注册。这种方式可以理解为通过代码注册的广播是和注册者关联在一起的。
使用场景:更新UI等及时性通信操作
优点:在Android的广播机制中,动态注册的优先级高于静态注册的优先级,因此在必要情况下,我们需要动态注册广播接收器。取消注册后,不再占用资源 。
示例如下:
//定义广播
class SmsReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
//doSomething
}
}
//注册广播
private SmsReceiver smsReceiver;
smsReceiver=new SmsReceiver();
IntentFilter intentFilter=new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
registerReceiver(smsReceiver,intentFilter);
//发送广播
Intent intent=new Intent();
intent.setAction("android.provider.Telephony.SMS_RECEIVED");
sendBroadcast(intent);
以上就是对于广播的理解和应用了。