Android广播机制——初体验
写在前面的话
文章为笔者自己理解 。
—如有错误,欢迎指正—
《第一行代码》读书笔记
写于2017年10月16日17:00:40
(一). 安卓广播的分类
a.标准广播
标准广播发出以后,所有的广播接收器,可以几乎在同一时刻同时接受到这条广播。
优点:效率高
缺点:不能被截断。
b.有序广播
有序广播发出以后,同一时刻只能有一个广播接收器收到这条广播。优先级高的广播先接受到这条
广播。在当前广播接收器处理完自己的逻辑以后,可以执行两种动作:
1.继续传递广播
2.将广播截断
(二). 注册广播的方式
a. 动态注册
在代码中注册的广播,被称为动态注册。动态注册的广播,最后必须取消注册。这类广播,只有应用启
动了,才能接收到广播。
动态注册广播需要的东西
一个广播接收器类 —— 实质就是一个继承自BoradCastReceiver的类,只要继承这个类,就
具体接收广播的能力了,但是能接受什么广播由下面的第三条决定。
重写父类的onReceive()方法 —— 接收到广播的时候,就会回调这个方法。因此,广播接收
器的处理逻辑就写在这里
一个 IntentFilter 对象,广播接收器接收什么样的广播,由它的addAction()方法决定。
在代码中注册广播接收器,通过registerReceiver方法。方法接受两个参数,一个是广播接收
器实例,一个是IntentFilter实例。
取消注册广播 ,通过unregisterReceiver() 方法—— 在哪里取消注册无所谓,只要保证取
消注册就OK
如果需要权限,则在AndroidManifest.xml文件申明权限
代码 :
布局代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<Button
android:text="检测网络"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:id="@+id/btn_isNetConnect" />
<TextView
android:textSize="30sp"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="80dp"
android:id="@+id/txt_show" />
</LinearLayout>
我们写一个简单的判断当前网络是否可用的广播。监听网络是一个敏感的动作,因此,需要在xml中申明权限。
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
java 代码
public class MainActivity extends AppCompatActivity {
// 决定广播接收器接收什么广播
private IntentFilter intentFilter ;
private NetworkChangeReceiver networkChangeReceiver ;
private TextView txt_show ;
private Button btn_isNetConnect ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取控件实例
txt_show = (TextView) findViewById(R.id.txt_show);
btn_isNetConnect = (Button) findViewById(R.id.btn_isNetConnect);
// 在按钮监听器中注册广播
btn_isNetConnect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
intentFilter = new IntentFilter() ;
// 字符串 android.net.conn.CONNECTIVITY_CHANGE
// 表明广播接收器接收网络变化的广播
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
// 网络变化广播接收器实例
networkChangeReceiver = new NetworkChangeReceiver() ;
// 注册广播
// 别忘了,申明权限
registerReceiver(networkChangeReceiver,intentFilter) ;
}
});
}
/**
* 动态注册的广播,必须在取消注册。
* 我们在create(),方法创建的时候,注册了广播
* 这里,我们在销毁活动中,取消注册,
* 当然也可以在onPause()方法取消注册。
*/
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(networkChangeReceiver);
}
/**
* 用内部类实现一个网络变化广播接收器
*/
class NetworkChangeReceiver extends BroadcastReceiver {
// 重写父类的onReceive()方法,接收到对应的广播的时候,就会回调这个方法
// 广播接收器的处理逻辑,就写此方法中
@Override
public void onReceive(Context context, Intent intent) {
// 获取网络管理服务类,就跟findViewById()方法一样
ConnectivityManager connectivityManager =
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
// 记住这样写。就好了。用到的时候,百度一下,边边角角,谁也记不清
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo() ;
// 判断网络状态
if(networkInfo != null && networkInfo.isAvailable()){
txt_show.setText("当前网络可用");
}else {
txt_show.setText("当前网络不可用");
}
}
}
}
b.静态注册
在AndroidManifest.xml文件中注册的广播。这类广播,常驻广播,在应用未启动的时候,即可接收
到广播,处理相应的逻辑。
静态注册的广播的广播接收器中不能有UI组件。
静态广播需要的东西
相比于动态注册的广播,静态广播需要的东西,就很少了。
依然需要一个广播接收器类
继续需要重写父类的onReceive()方法
在AndroidManifest.xml文件中注册广播
如果需要权限,则在AndroidManifest.xml文件申明权限
talk is cheap,show me code ! Or shut up
代码:
/**
* 这里写将广播写为内部类
* 目的;记住一个知识点:
* 静态注册的广播,广播接收器为内部类的时候,必须是pubic static
* 实现开机自启动
* Created by MaiBenBen on 2017/10/16.
*/
public class Outter {
// 必须是public static
public static class BootCompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// 调启主活动,来打开应用程序
// context参数,就是此时的上下文
Intent intent1 = new Intent(context,MainActivity.class);
context.startActivity(intent1);
}
}
}
<!--
在AndroidManifest.xml文件中注册广播
内部类广播接收器的名字,写全了
-->
<receiver android:name=".Outter$BootCompleteReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<!--写明广播接收器接收的广播-->
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
</intent-filter>
</receiver>
监听开机广播 权限申明:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"></uses-permission>
至此,已经成功完成了开机自启动。
(三). 发送广播
总是接受广播,也没劲。下面,我们自己来发送一些广播。发送的广播是自定义的。
a. 发送标准广播
广播是使用Intent,进行传递的。因此,我们可以在Intent中携带一些数据传递给广播接收器。
注意:这里只是在活动中发送广播,在服务或者广播中发送广播,代码有所不同:需要在intent中加上
标志。
setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)。
该标志表明:首先寻找是否有与要启动的activity具有相同affinity的task。若没有,则生成一个新
的task,并将该activity放入其中;若有,则将该activity添加到该task的栈顶。
// 自定义广播内容
String broadcast = "allbet.broad.cn.broadcasttest.MY_BROADCAST" ;
// 绑定到Intent中
Intent intent = new Intent(broadcast) ;
// 发送广播,调用Context的sendBroadcast()方法
sendBroadcast(intent);
b. 发送有序广播
有序广播与标准广播的发送方式,在代码中只有一句代码有差别,就是发送广播的方法不同。
// 自定义广播内容
String broadcast = "allbet.broad.cn.broadcasttest.MY_BROADCAST" ;
// 绑定到Intent中
Intent intent = new Intent(broadcast) ;
// 发送有序广播
// 第一个参数依然是Intent
// 第二个参数是代表权限的字符串,这里写null就好了
sendOrderedBroadcast(intent,null);
有序广播发送完毕以后,优先级高的广播接收器会先收到这
个广播。它们甚至可以将广播截,下面我们讲一下优先级的
问题
<☆> 广播接收器优先级
1.) 静态广播的优先级
跟目录的顺序有关,如下所示,目录越靠前,优先级越高,其中,第三方APP都在data/app目
录下:
system/framework
system/appvendor/app
data/app
drm/app-private
当处于同一目录下时:按照file.list()的返回顺序。因为在data/app下的应用都是用户安装的,
并且都是以com.xxx.xxx-1.apk 的形式出现,它们的顺序,就是包名的顺序,因此,想要你的
应用的静态广播优先级高,就需要好好研究包名了,让你的应用包名靠前。但是这个顺序不是
绝对的,还依赖被扫描的先后顺序,先扫描的当然优先级高一点啦。即同一优先级的静态广播
接收器,先扫描的优先级高。一般都是包名排在前面的先被扫描。但是有人也说,是按照应用
安装的先后顺序。。。。有待考证
上面说的都是静态注册的时候,使用了相同优先级的情况。设置了优先级的,优先级越高,越
先接收到广播。
2.) 动态广播的优先级
一大影响因素,动态广播的注册时间。同一优先级的动态广播,先注册的优先级高。
动态注册的广播接收器的优先级永远高于静态注册的广播接收器。
综上所述,做个总结:
其实当接收广播的时候,广播接收器都会排队,无论是标准广播,还是有序广播,都是要排队
的,只不过,有序广播可能会被截断。
因此我们可以将,所有能接收该广播的广播接收器,理解为排队等着广播传递,排在前面的
人,当然就先接收到广播啦。那么谁排在前面呢?毫无疑问,一定是动态注册的广播,动态注
册的广播接收器们根据优先级排队,相同优先级的,就按照被扫描的先后顺序排队。排在队伍
后面的就只剩下静态注册的广播接收器了,也先根据优先级排序,相同优先级的,按照被扫描
的先后顺序排队。
上述的情况是,所有的广播接收器都不缺席的情况,但是总有广播接收器,由于种种原因(比
如,动态注册的广播,应用未启用)会缺席,缺席的话,那后面的广播接收器就自动补全空
位。
(四).为广播接收器设定优先级
a.为静态广播接收器设定优先级
在xml文件中设定
<receiver android:name=".Outter$BootCompleteReceiver"
android:enabled="true"
android:exported="true">
<!--在这里添加属性-->
<intent-filter android:priority="100">
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
</intent-filter>
</receiver>
b.为动态广播设置优先级
在intentFilter对象上设置
intentFilter = new IntentFilter() ;
// 字符串 android.net.conn.CONNECTIVITY_CHANGE
// 表明广播接收器接收网络变化的广播
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
// 设置优先级
intentFilter.setPriority(1000);
// 网络变化广播接收器实例
networkChangeReceiver = new NetworkChangeReceiver() ;
// 注册广播
// 别忘了,申明权限
registerReceiver(networkChangeReceiver,intentFilter) ;
(五).截断有序广播
有序广播在传送中,是可以被截断,甚至可以修改广播携带的数据。
截断广播,就是在广播接收器的onReceive()方法中调用abortBroadcast();
public void onReceive(Context context, Intent intent) {
/*
处理逻辑
*/
// 逻辑处理结束,截断广播。
abortBroadcast();
}
(六) 本地广播
之前我们发送的广播,都是系统全局广播,即我们发送的广播,能被系统的其他程序也接收到。这样是
很不安全的,因为,广播上说不定会携带着关键数据。或者,其他程序,不停的向我们发生垃圾广播。
本地广播,是无法再通过静态注册的广播接收器收到的。很好理解,静态注册,是为了程序未启动的
时候接收广播,而本地广播,程序已然启动可了。当然,也不能注册本地广播。
因此,我们需要本地广播,顾名思义,广播,只能在本程序中发送和接收。
a.本地广播需要的东西
- 对比全局广播,本地广播需要一个LocalBroadcastManger对象,来对广播进行管理。
// 获取本地广播管理 实例
localBroadcastManager = LocalBroadcastManager.getInstance(this);
intentFilter = new IntentFilter("com.yaz.QQQ") ;
myLocalBr = new MyLocalBr() ;
localBroadcastManager.registerReceiver(myLocalBr,intentFilter);
break;
这里需要注意的事:本地广播是不能静态注册,主要是为了别的程序申明和intent-filter一样的广播。
last but not least:一些小技巧
- 如果程序需要在某个时候,接受到一个广播,这个广播中需要弹出一些UI组件。
- 由于时间的不确定性,有可能在任何一个活动上,接收到这个广播。
- 因此,第一反应,就是注册静态广播,毕竟,动态广播,跟随活动。
- 但是,由于有UI组件需要弹出,静态广播是不能注册了。
- 完犊子,只有为活动一个一个注册广播接收器了。
上述方法,多呆哦!
思路:为了解决这个问题,我们可以写一个活动基类,让它继承活动的上帝类Activity;再让其他的活动类继承这个活动基类。聪明的你,可能已经想到了java的继承特性了。对!我们,就在这个活动基类中的onResume()方法中注册广播,这样后面所有活动类,启动完毕以后,处于栈顶的是,就会执行这个方法,完成广播的注册。那么广播的取消注册呢?当然同样放在活动基类中,至于放在哪一个方法中呢?我们放在,onStop()方法中,方法不在栈顶,就取消注册。这个方法,视情况而定。 就这样,我们完成了动态广播的重复注册。
Allbet
写于2017年10月17日20:23:14
Android广播机制——初体验的更多相关文章
- Android随笔之——Android广播机制Broadcast详解
在Android中,有一些操作完成以后,会发送广播,比如说发出一条短信,或打出一个电话,如果某个程序接收了这个广播,就会做相应的处理.这个广播跟我们传统意义中的电台广播有些相似之处.之所以叫做广播,就 ...
- Android广播机制的深入学习
部分内容转载自http://www.cnblogs.com/lwbqqyumidi/p/4168017.html 1.Android广播机制概述 Android广播分为两个方面:广播发送者和广播接收者 ...
- Android总结篇系列:Android广播机制
1.Android广播机制概述 Android广播分为两个方面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的就是广播接收者(广播接收器).广播作为Android组件间的通 ...
- Android广播机制概述
1.Android广播机制概述 Android广播分为两个方面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的就是广播接收者(广播接收器).广播作为Android组件间的通 ...
- Android广播机制:Broadcast
转载:Android总结篇系列:Android广播机制 1.Android广播机制概述 Android广播分为两个方面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的就是广 ...
- Android(java)学习笔记172:BroadcastReceiver之 Android广播机制
Android广播机制 android系统中有各式各样的广播,各种广播在Android系统中运行,当"系统/应用"程序运行时便会向Android注册各种广播.Android接收到广 ...
- Android广播机制(转)
1.Android广播机制概述 Android广播分为两个方面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的就是广播接收者(广播接收器).广播作为Android组件间的通 ...
- Android广播机制
原文出处: Android总结篇系列:Android广播机制 1.Android广播机制概述 Android广播分为两个方面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的 ...
- Android(java)学习笔记115:BroadcastReceiver之 Android广播机制
Android广播机制 android系统中有各式各样的广播,各种广播在Android系统中运行,当"系统/应用"程序运行时便会向Android注册各种广播.Android接收到广 ...
随机推荐
- project.config.json在设置了编译模式的时候会出现配置,怎么解决
因为之前为了方便就选了一个页面进行编译,但是想想回到index首页,就编译了一个pages/index/index. 出现了上面这个,当我再选择编译的时候,还是不会变成之前的. 解决方法是 把红框那段 ...
- Echarts:实现拖拽效果
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script sr ...
- Spring Boot AOP 简易操作日志管理
AOP (Aspect Oriented Programming) 面向切面编程. 业务有核心业务和边缘业务. 比如用户管理,菜单管理,权限管理,这些都属于核心业务. 比如日志管理,操作记录管理,这些 ...
- 关于 array of const
之前应该参考一下: 关于开放数组参数 //这是在 System 单元定义的一组标识数据类型的常量: vtInteger = ; vtBoolean = ; vtChar = ; ...
- 表单在ios下输入框必须重压或长按才能唤起软键盘
解决方案: 一.在node_module里找到fastClick文件,然后找到focus方法,加一句focus方法即可解决:FastClick.prototype.focus = function(t ...
- typeScript模块<一>
/*模块 模块的的概念 模块导出的几种方法 1.export 导出声明 2.export 导出语句 3.export default 4.import导入模块 模块化封装上一讲的DB库 */ /* 模 ...
- OpenGL ES3使用MSAA(多重采样抗锯齿)的方法
昨晚花费了我2个多小时的时间终于把OpenGL ES3.0中的MSAA给搞定了.在OpenGL ES2.0中,Khronos官方没有引入标准的MSAA全屏抗锯齿的方法,而Apple则采用了自己的GL_ ...
- 超级简单的checkbox赋值,用于记住登陆名
<input name="rememberme" type="checkbox" id="rememberme" onclick=&q ...
- django项目mysite
项目建立 建立项目mysite 各文件和目录解释: 外层的mysite/目录与Django无关,只是你项目的容器,可以任意重命名. manage.py:一个命令行工具,用于与Django进行不同方式的 ...
- c# 在静态方法里,怎么能得到调用者的类名?
System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace(); string name = st.GetFrame(1) ...