广播:BoradcastReceiver
1 、BoradcastReceiver的作用?
Broadcast receiver 是一个用来响应系统范围内的广播的组件。 很多广播发自于系统本身。—例如, 通知屏幕已经被关闭、电池低电量、照片被拍下的广播。 应用程序也可以发起广播。—例如, 通知其它程序,一些数据被下载到了设备,且可供它们使用。 虽然广播并不提供用户交互界面,它们也可以创建一个状态栏通知 来提醒用户一个广播事件发生了。尽管如此,更多的情形是,一个广播只是进入其它组件的一个“门路”,并试图做一些少量的工作。 例如,它可能发起一个服务,并通过服务执行与这个广播事件相关的工作。
数据传输与共享,比如系统自带广播,开机广播,电量广播,短信,电话广播等。
起到通知的作用,比如在收到广播后,开启Service,启动Activity,或者进入网络查询或者更新Ui界面;
在android中比较常用的情景是Activity与startService()方法的启动通过BroadcastReceiver()来实现
2、生命周期
developer上的描述:
翻译:
广播生命周期
一个BroadcastReceiver对象仅适用执行在onReceive的时间上(上下文,意图)。一旦你的代码返回这个函数,系统考虑的对象将完成,不再活跃。
这具有重要的影响,你可以做什么在onReceive(上下文,意图)执行:任何需要异步操作是不可用的,因为你需要从函数中返回处理异步操作,但在这一点上,BroadcastReceiver不再活跃,因此系统在执行异步操作前已经将它杀死。
特别是,你可能不会显示一个对话框或绑定到一个服务从一个BroadcastReceiver中。对于前者,你应该使用NotificationManager API。对于后者,你可以使用上下文。startservice()将命令发送到服务。
3、 广播中为什么不能做耗时操作,或者开子线程进行耗时操作?
在广播中当调用了onReciver()方法并传递它包含消息的intent对象,广播接收者认为当它执行这个方法的时候为活跃的,当onReceive()执行后,它是不活跃的。活跃的广播接收者进程是受保护的,不会被杀死, 但系统可以在任何时候杀死不活跃的进程,特别是内存吃紧的时候。如果在广播中作耗时操作,并且onReceive()方法执行后,开的子线程没有执行完,有可能广播已经被销毁了,并且每次发送的广播都会创建BroadcastReceiver的实例。因此, BroadcastReceiver中不能作耗时操作,如果超过10秒中就是报ANR异常;
如果要做耗时操作的话,应该在广播中用intent开启一个Service,在服务中开启线程,做耗时操作;
4、两种开启广播的方式:
1、静态注册,在清单文件中注册,这种广播开启的方式比较常用。即使应用退出了,广播也能接收到消息。
2、动态注册(与Service的bindService相似): 就是在代码中注册,不用在清单文件中注册但这注册方式启动的广播,要在组件销毁的时候,解除注册,如果不解除退出程序可能报错。
5、有序广播和无序广播
developer描述:
翻译:
普通广播(Context.sendBroadcast)是完全异步的。广播的所有接收器都运行在未定义的顺序中,通常在同一时间。这是更有效的,但这意味着接收器不能使用的结果在广播中中止。
有序广播(Context.sendorderedbroadcast)被传递到一个接收器中。由每个接收端执行,它可以向下一个接收器传递一个广播,或者它可以完全中止广播,以便它不会被传递给其他接收器。在可与安卓控制的顺序接收器中,匹配的意图过滤器的优先级属性,与相同优先级的接收器将在任意顺序运行。
普通广播:通过sendBroadcast()方法来发送。通过这种形式发送广播接收的顺序也是不确定的。但效率比较高
有序广播:是通过sendOrderedBroadcast来发送。按优先级的不同,优先Receiver可对数据进行处理,并传给下一个Receiver效率比较低。可以在清单文件中设置优先级从-1000-1000;
<intent-filter android:priority="1000">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>-->
终止广播:abrotBroadcast()
当android系统接收到短信时,会发送一个广播BroadcastReceiver(),这个广播是有序的形式发送的。
短信拦截器的功能就是把BroadcastReceiver的优先级设置的比较系统高,当收到这条广播时,终止广播。这样就可以拦截短信了
1、静态的方式创建广播,以接收到短信为例:
在xml文件中注册:
<receiver android:name=".MsgReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
添加权限:
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
在MsgReceiver()中的代码:
public class MsgReceiver extends BroadcastReceiver {
private static final String TAG = "MsgReceiver";
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
SmsMessage[] smsMessages = null;
Object[] pdus = null;
if (bundle != null) {
pdus = (Object[]) bundle.get("pdus");
}
if (pdus !=null){
smsMessages = new SmsMessage[pdus.length];
String sender = null;
String content = null;
for (int i=0; i<pdus.length; i++){
smsMessages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
sender = smsMessages[i].getOriginatingAddress();
content = smsMessages[i].getMessageBody();
Log.i(TAG, "SMS:"+sender+content);
}
}
}
}
在activity中什么也不做,发送短信给10086则:
从log中可以看到短信内容为:
2、通过动态的方式注册广播,也就是在代码中注册(这种方式的注册广播使用的比较少,因为它需要手机注销广播,如果没有注销广播,退出时发报异常)
在MyReceiver()中代码:
public class MyReceiver extends BroadcastReceiver {
private static final String TAG="MyReceiver";
private String msg;
@Override
public void onReceive(Context context, Intent intent) {
//在发送广播时的标识
if(intent.getAction().equals("a")){
msg=intent.getStringExtra("name");
};
Log.i(TAG, msg);
}
}
在MainActivity中的注册代码:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
public static final String TAG_ID="";
private Button btn_send;
private MyReceiver receiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_send = (Button) findViewById(R.id.btn_send);
btn_send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
receiver = new MyReceiver();
//意图过滤器,过滤Intent;
IntentFilter filter = new IntentFilter();
filter.addAction("a");
//注册广播;
registerReceiver(receiver, filter);
//在Intent中携带数据,也可以用Bundle
Intent intent =new Intent();
//发送广播时的设置的一个标识,用于标识是从哪里发过来。
intent.setAction("a");
//也可以能过Bundle打包传递数据;
intent.putExtra("name", "csdn");
//发送广播
sendBroadcast(intent);
Log.i(TAG, "发送广播");
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
//解除注册;
if(receiver!=null) {
unregisterReceiver(receiver);
}
}
}
通过这种方式开启的广播在退出应用时,一定要注销广播。