简介
BroadCastReceiver:广播接收者,可以接受手机电量变化、短信、电话、app的安装与卸载等都可以接受到这些广播(这些事系统发出的广播),当然我们还可以自定义广播,这就我们自己写发送广播的代码。
分类:
有序广播和无序广播
有序广播:是可以拦截的,可以设置优先级(数值越大,越先接收广播)
无序广播:不可以被拦截,没有优先级。
有关方法:
sendBroadcast(intent);
发送广播
sendOrderedBroadcast(Intent intent, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)
发送有序广播
abortBroadcast();
取消广播,只有有序广播才可以调用该方法,无序广播调用会报错BroadcastReceiver trying to return result during a non-ordered broadcast
如果是静态广播,那么不需要在onReceive(...)
中判断action
,如果是动态注册,需要判断action
静态广播接收者BroadCastReceiver
注册广播接收者有2种方法,代码中注册(动态注册)和AndroidManifest.xml中注册(静态注册),下面的案例没说明动态注册的都是静态注册。
系统发出的广播,我们只做接收。常见的如下:
- 打电话 Receiver
- SD卡状态 Receiver
- 来短信 Receiver
- app的安装与卸载 Receiver
- 开机启动 Receiver
打电话 Receiver
打电话,若是长途,则广播中给手机号添加ip:123456
@Override
public void onReceive(Context context, Intent intent) {
//获取保存的ip
SharedPreferences sp = context.getSharedPreferences("config", context.MODE_PRIVATE);
String ip = sp.getString("ip", "17951");
//获取拨进来的号码
String number = getResultData();
//以0开头,则是长途,则在号码前加ip
if (number.startsWith("0")) {
setResultData(ip + number);
}
}
<!--在androidManifest中注册的广播是持久广播,app退出仍然有效。 -->
<!-- 声明receiver 添加action -->
<receiver android:name="com.cqc.ipnumber.OutGoingCallBroadCastReceiver" >
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
<!-- 添加外拨电话权限 -->
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
SD卡状态 Receiver
根据action判断sd卡是挂载还是卸载。注意卸载sd卡的action是UNMOUNTED,不是REMOVE
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_MEDIA_MOUNTED.equals(action)) {// 挂载
Log.d(TAG, "sd卡挂载");
} else if (Intent.ACTION_MEDIA_UNMOUNTED.equals(action)) {
Log.d(TAG, "sd卡卸载");
}
}
<!-- 声明receiver -->
<receiver android:name="com.cqc.sdstatelistener.SdStateReceiver" >
<intent-filter>
<action android:name="android.intent.action.MEDIA_MOUNTED" />
<action android:name="android.intent.action.MEDIA_UNMOUNTED" />
<!-- sd卡状态比较特殊,除了设置action,还需要data -->
<data android:scheme="file" />
</intent-filter>
</receiver>
来短信 Receiver
广播接收者:
@Override
public void onReceive(Context context, Intent intent) {
//转换成数组
Object[] objects = (Object[]) intent.getExtras().get("pdus");
//遍历数组,湖区sms对象
for (Object object : objects) {
SmsMessage sms = SmsMessage.createFromPdu((byte[]) object);
//获取短信内容和发布者手机号
String content = sms.getMessageBody();
String originNumber= sms.getOriginatingAddress();
Log.d(TAG, "content="+content+"____originNumber"+originNumber);
}
}
<receiver android:name="com.cac.smsreceiver.SmsReceiver" >
<intent-filter>
<!-- 处于安全性考虑,android没有提示短信监听的action,但仍然可以使用 -->
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
<!-- 短信监听的权限 -->
<uses-permission android:name="android.permission.RECEIVE_SMS" />
把androidManifest.xml的启动的actiivty的intent_filter注释掉,就没有界面了,但是海驿拿到短信, api4.0后,注释掉intent_filter,就拿不到短信了。
app的安装与卸载 Receiver
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {// 挂载
Log.d(TAG, "安装");
} else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
Log.d(TAG, "卸载");
}
}
<receiver android:name="com.cqc.installreceiver.InstallReceiver">
<intent-filter >
<action android:name="android.intent.action.PACKAGE_ADDED"/>
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
<!-- 安装卸载还需要添加data -->
<data android:scheme="package"/>
</intent-filter>
</receiver>
开机启动 Receiver
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "intent2");
Intent intent2 = new Intent(context, MainActivity.class);
intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent2);
String action = intent.getAction();
if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
Log.d(TAG, "Intent.ACTION_BOOT_COMPLETED");
}
}
<receiver android:name="com.cqc.bootreceiver.BootReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
自定义广播接收者
自定义广播需要设置action,可以获取intent中的数据。
基本使用
自定义广播,在Button的点击监听中发送广播,在receiver中根据action,从intent中取值。
发送广播:
Intent intent = new Intent();
intent.setAction("MyReceiver");
intent.putExtra("name", "奥巴马");
sendBroadcast(intent);
MyReceiver :
public class MyReceiver extends BroadcastReceiver {
private static final String TAG = "MyReceiver";
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "MyReceiver--name="+intent.getStringExtra("name"));
//取消广播
abortBroadcast();
}
}
在AndroidManifest.xml中配置receiver:
<receiver android:name="com.cqc.custombroadcast.MyReceiver">
<intent-filter >
<action android:name="MyReceiver"/>
</intent-filter>
</receiver>
自定义有序广播
demo:国家发布政令后,先到省政府,再到市政府,再到县政府…,这里只设置这3级,有先后顺序。点击Button发送广播,一次向下传递。
点击Button发送广播:
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//发送自定义广播
Intent intent = new Intent();
intent.setAction("customOrderReceiver");
intent.putExtra("commond", "全国各级部门应该加强安全防范措施");
// sendBroadcast(intent);//这是无序广播
/**
* 这是有序广播,参数分别是:
* Intent intent:intent对象
* String receiverPermission: 接收者权限
* BroadcastReceiver resultReceiver:最后一个接收者,不为null,则最后的receiver会接收2次。
* Handler scheduler, null
* int initialCode 状态码
* String initialData, 传递的数据,intent.putExtra(...)
* Bundle initialExtras:null
*/
sendOrderedBroadcast(intent, null, new CountyReceiver(), null, 1, null, null);
}
});
省级先接到通知
public class ProviceReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("tag", "省级部门接到中央命令+content="+intent.getStringExtra("commond"));
}
}
然后是市级接到通知
public class CityReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("tag", "市级部门接到中央命令+content="+intent.getStringExtra("commond"));
}
}
最后是县级接到通知
public class CountyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("tag", "县级部门接到中央命令+content="+intent.getStringExtra("commond"));
}
}
注意:
1 上面的先后级别是根据广播接收者的priority(优先级)决定的。是在配置receiver时设置的。
<receiver android:name="com.cqc.customorderreceiver.ProviceReceiver" >
<intent-filter android:priority="3" >
<action android:name="customOrderReceiver" />
</intent-filter>
</receiver>
<receiver android:name="com.cqc.customorderreceiver.CityReceiver" >
<intent-filter android:priority="2" >
<action android:name="customOrderReceiver" />
</intent-filter>
</receiver>
<receiver android:name="com.cqc.customorderreceiver.CountyReceiver" >
<intent-filter android:priority="1" >
<action android:name="customOrderReceiver" />
</intent-filter>
</receiver>
2 调用方法sendOrderedBroadcast(…)发送有序广播的时候若指定了最后接收者( resultReceiver),那么 resultReceiver会收到2次广播。
动态注册广播接收者
与静态相比区别是:
代码上:
1 不需要再AndroidManifest.xml中注册
2 调用registerReceiver(receiver, filter)注册接收者
理解上:
静态注册的广播接收者:当app关闭的时候也是有效的,也可以接受到服务器发出的广播。
动态注册的广播接收者:当app关闭的时候,不会接受到广播。因为我们是在onCreate()中注册的,而不是在AndroidManifest.xml中注册。
下面的是锁屏和开锁的的广播接收者,当我们打开这个app的时候,按住手机电源键锁屏和接收会打印出log,但是当我们关闭app的时候,再按住手机电源键锁屏和接收则不会打印出log
Demo1:
public class MainActivity extends Activity {
private MyBroadcastReceiver receiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
receiver = new MyBroadcastReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.SCREEN_ON");//添加action
filter.addAction("android.intent.action.SCREEN_OFF");
registerReceiver(receiver, filter);//注册广播接收者
}
@Override
protected void onDestroy() {
unregisterReceiver(receiver);//取消广播接收者
super.onDestroy();
}
//创建广播接收者类
public class MyBroadcastReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if ("android.intent.action.SCREEN_OFF".equals(action)) {
System.out.println("锁屏");
} else if("android.intent.action.SCREEN_ON".equals(action)){
System.out.println("解锁");
}
}
}
}
代码:https://git.oschina.net/beifang2008/DongTaiBroadCastReceiver
Demo2:
public class MainActivity extends Activity {
private MyBroadcastReceiver receiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("auto_finish");
sendBroadcast(intent);
}
});
receiver = new MyBroadcastReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("finish");// 添加action
registerReceiver(receiver, filter);// 注册广播接收者
}
@Override
protected void onDestroy() {
unregisterReceiver(receiver);// 取消广播接收者
super.onDestroy();
}
// 创建广播接收者类
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if ("finish".equals(action)) {
finish();
}
}
}
}
sendBroadcast(intent)与sendStickyBroadcast(intent)的区别?
区别主要是在动态注册广播中才有,在静态注册中是一样的。
sendBroadcast(intent):当发送广播在注册广播前时,接收者是接收不到广播的。
sendStickyBroadcast(intent):当发送广播在注册广播前时,接收者是可以接收到广播的。sendStickyBroadcast发出的最后一个Intent会被保留,下次当Recevier处于活跃的 时候,又会接受到它。
Demo:https://git.oschina.net/beifang2008/DongTaiBroadCastReceiver2
LocalBroadcastManager
Android高效安全的本地广播LocalBroadcast完全解析
LocalBroadcastManager
只可以动态注册广播。
获取LocalBroadcastManager
对象,单利模式
LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(this);
设置InentFilter,intentFilter和intent都必须设置action
IntentFilter filter = new IntentFilter();
filter.addAction(localAction);
注册
broadcastManager.registerReceiver(receiver, filter);
发送Broadcast
Intent intent = new Intent(localAction);
broadcastManager.sendBroadcast(intent);
取消注册
broadcastManager.unregisterReceiver(receiver);
android.support.v4.content.LocalBroadcastManager工具类,可以实现在自己的进程内进行局部广播发送与注册,使用它比直接通过sendBroadcast(Intent)发送系统全局广播有以下几个好处
- 因广播数据在本应用范围内传播,你不用担心隐私数据泄露的问题。
- 不用担心别的应用伪造广播,造成安全隐患。
- 相比在系统内发送全局广播,它更高效。