学之广在于不倦,不倦在于固志。 ——晋·葛洪
(学问的渊博在于学习时不知道厌倦,而学习不知厌倦在于有坚定的目标)
001.BroadcastReceiver简介:
广播接收者,安卓四大组件之一,在安卓领域有着广泛的应用,比如:
系统开机广播:
当开机完成之后系统会发送一条广播,接收到这条广播就能实现开机启动服务的功能
电量变化广播:
当电池电量发生改变时,系统会产生一条广播,接收到这条广播就能在电量低时告知用户及时保存进度
网络变化广播:
当网络状态改变时系统会产生一条广播,接收到这条广播就能及时地做出提示和保存数据等操作
强制下线广播:
当我们的账户被他人登录时,服务端就会推送一条广播,我们接收到这个广播就会强制用户下线重新登录
等等,还有很多的广播
Android中广播主要分为标准广播和有序广播:
标准广播:
--> 是一种完全异步的广播,在广播发出去之后,所有的广播接收者几乎在同一时间接收到这条广播,因此它们之间没有先后顺序
--> 发送方式:sendBroadcast();
--> 优点是效率比较高效
--> 缺点是无法控制、修改
有序广播:
--> 是一种同步执行的广播,在广播发出去之后,同一时刻只会有一个广播接收者能够接收到这条广播,当这个广播接收器中的逻辑执行完毕之后,广播才会继续传递
--> 发送方式:sendOrderBroadcast();
--> 优点有先后顺序,优先级(priority属性来设置优先级,范围-1000~1000)高的广播接收器先接收到,可以对接收到的广播进行截断、编辑修改
注意:
广播还有其他类型,比如:
系统广播(System Broadcast):
--> 只要涉及到手机的基本操作(如开机、网络状态变化、拍照等等),都会发出相应的广播
--> 每个广播都有特定的Intent - Filter(包含具体的action),具体请点击此处参考
--> 当使用系统广播时,只需要在清单文件注册广播接收者时定义相关的action即可,并不需要手动发送广播,当系统有相关操作时会自动进行系统广播,只需要创建广播接收者进行相关操作即可
粘性广播(Sticky Broadcast):
--> 由于在Android5.0 & API 21中已经失效,所以不建议使用
本地广播(Local Broadcast):
--> 可理解为一种局部广播,广播的发送者和接收者都同属于一个App,使用这种机制发出的广播只能够在应用程序内部进行传递
--> 相比于全局广播(上面的几种),本地广播优势体现在:安全性高 & 效率高
--> 本地广播无法通过静态注册方式来接收
002.广播的具体使用及代码实战:
实现步骤:
0a、创建广播接收者
--> 新建一个类,让它继承BroadcastReceiver并重写父类的onReceiver()方法
--> 当有广播到来时,onReceiver()方法就会执行,具体的逻辑就可以在该方法中进行
0c、注册广播
--> 分为动态注册和静态注册(具体看下面代码)
--> 两者区别:
动态注册属于非常驻型广播,比较灵活,生命跟随所注册的组件,组件退出广播退出,在退出广播时必须移除广播接收者,否则会造成内存泄漏,必须在程序启动后才能接收到广播
静态注册属于常驻型广播,不受任何组件的生命周期影响,在应用关闭之后,若有广播来临也可以接收广播,耗电、占内存
--> 注意,广播的注册和取消建议在onResume和onPause,因为onPause()在App死亡前一定会被执行,从而保证广播在App死亡前一定会被注销,从而防止内存泄露
0b、发送广播
-->标准及其他广播使用:sendBroadcast()
-->有序广播使用:sendOrderBroadcast()
代码实战:
0a、标准广播:点击按钮发送广播,收到广播弹出提示
1> 动态注册广播
public class MainActivity extends AppCompatActivity { private IntentFilter mFilter; private MyBroadcastReceiver mReceiver; private static final String MYBROADCAST_ACTION = "com.example.mycast.MyBroadcastReceiver"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //点击按钮发送广播 findViewById(R.id.bt_register).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(MYBROADCAST_ACTION); sendBroadcast(intent); } }); } /** * 动态注册广播 */ @Override protected void onResume() { super.onResume(); //构建IntentFilter并添加Action mFilter = new IntentFilter(); //接收的广播类型 mFilter.addAction(MYBROADCAST_ACTION); //创建广播接受者 mReceiver = new MyBroadcastReceiver(); //注册广播 registerReceiver(mReceiver, mFilter); } /** * 标准广播接收者:当有匹配的广播到来时,onReceiver()方法就会执行,具体信息 * 保存在Intent中,具体得到处理就需要在此方法中进行 */ class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "Received in MyBroadcastReceiver!", Toast.LENGTH_LONG).show(); } } /** * 动态注册的广播一定要移除广播接收者 */ @Override protected void onPause() { super.onPause(); unregisterReceiver(mReceiver); } }
2>静态注册广播
清单文件注册
<receiver android:name=".MainActivity$MyBroadcastReceiver"> <intent-filter> <action android:name="com.example.mycast.MyBroadcastReceiver"/> </intent-filter> </receiver>
public class MainActivity extends AppCompatActivity { private static final String MYBROADCAST_ACTION = "com.example.mycast.MyBroadcastReceiver"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //点击按钮发送广播 findViewById(R.id.bt_register).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(MYBROADCAST_ACTION); sendBroadcast(intent); } }); } /** * 标准广播接收者:当有匹配的广播到来时,onReceiver()方法就会执行,具体信息 * 保存在Intent中,具体得到处理就需要在此方法中进行 */ public static class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "Received in MyBroadcastReceiver!", Toast.LENGTH_LONG).show(); } } }
0b、有序广播:点击项目的发送,进行信息的修改,后续广播发生变化
项目1,设置优先级为100
<receiver android:name=".MainActivity$MyBroadcastReceiver"> <intent-filter android:priority="100"> <action android:name="com.example.mycast.MyBroadcastReceiver"/> </intent-filter> </receiver>
public class MainActivity extends AppCompatActivity { private static final String MYBROADCAST_ACTION = "com.example.mycast.MyBroadcastReceiver"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //点击按钮发送有序广播 findViewById(R.id.bt_register).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(MYBROADCAST_ACTION); intent.putExtra("msg", " One Message Send!!"); sendOrderedBroadcast(intent, null); } }); } /** * 标准广播接收者:当有匹配的广播到来时,onReceiver()方法就会执行,具体信息 * 保存在Intent中,具体得到处理就需要在此方法中进行 */ public static class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(MYBROADCAST_ACTION)) { String msg = intent.getStringExtra("msg"); //显示我们传递的信息 Toast.makeText(context, "Received in MyBroadcastReceiver!" + msg, Toast.LENGTH_SHORT).show(); //有序广播进行信息的修改 Bundle extras = new Bundle(); extras.putString("msg", msg+"已经过加工"); //继续向下传 setResultExtras(extras); } } }
项目2,设置优先级为99
<receiver android:name=".AnotherBroadcastReceiver"> <intent-filter android:priority="99"> <action android:name="com.example.mycast.MyBroadcastReceiver"/> </intent-filter> </receiver>
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
public class AnotherBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals("com.example.mycast.MyBroadcastReceiver")) { //获取广播的原始信息 String msg = intent.getStringExtra("msg"); //获取广播经过修改的信息 Bundle bundle = getResultExtras(true); String change = bundle.getString("msg"); //显示2种信息 Toast.makeText(context, "Received in AnotherBroadcastReceiver!" + change + "," + msg, Toast.LENGTH_SHORT).show(); } } }
0c、系统广播:动态注册系统网络状态变化广播
广播接收者
/** * 接收广播:当有匹配的广播到来时,onReceiver()方法就会执行,具体信息 * 保存在Intent中,具体得到处理就需要在此方法中进行 */ class NetworkReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { //ConnectivityManager: 系统用于管理网络连接的服务类 ConnectivityManager manager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo info = manager.getActiveNetworkInfo(); //通过NetworkInfo的isAvailable()方法判断当前是否有网络,并提示信息 if (null != info && info.isAvailable()) { Toast.makeText(context, "Network is Available !!", Toast.LENGTH_LONG).show(); } else { Toast.makeText(context, "Network is unAvailable !!", Toast.LENGTH_LONG).show(); } } }
动态广播注册(因为是系统广播会自动发送广播)
private IntentFilter mFilter; private NetworkReceiver mReceiver; private static final String NETWORK_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
/**
* 动态注册广播
*/
@Overrideprotected void onResume() {
super.onResume();
//构建IntentFilter并添加Action
mFilter = new IntentFilter();
mFilter.addAction(NETWORK_ACTION);
//创建广播接受者
mReceiver = new NetworkReceiver();
//注册广播
registerReceiver(mReceiver, mFilter);
}
注意需要在清单文件配置:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
当系统的网络状况发生改变时,就会提示相应的变化
0d、系统广播:静态注册开机广播
广播接收者
/** * 监听开机广播 */ public static class BootCompleteReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "Boot Completed !!", Toast.LENGTH_LONG).show(); } }
静态注册系统广播
<receiver android:name=".MainActivity$BootCompleteReceiver"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"/> </intent-filter> </receiver>相关权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
在模拟机开机后,会弹出提示“Boot Completed !!”广播
0e、本地广播:
/** * 本地广播安全、高效,属于局部广播,在App内部才有效 */ public class MainActivity extends AppCompatActivity { private LocalBroadcastManager mLocalBroadcastManager; private LocalReceiver mLocalReceiver; private IntentFilter mFilter; private static final String LOCAL_ACTION = "com.test.okamiy.broadcast.LOCAL_BROADCAST"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //点击发送本地广播 findViewById(R.id.bt).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(LOCAL_ACTION); //发送广播 mLocalBroadcastManager.sendBroadcast(intent); } }); } /** * 广播接收者 */ class LocalReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "Received Local Broadcast!", Toast.LENGTH_SHORT).show(); } } /** * 注册本地广播 */ @Override protected void onResume() { super.onResume(); //获取本地广播实例,用来注册和发送广播 mLocalBroadcastManager = LocalBroadcastManager.getInstance(MainActivity.this); mFilter = new IntentFilter(); mFilter.addAction(LOCAL_ACTION); mLocalReceiver = new LocalReceiver(); //注册本地广播 mLocalBroadcastManager.registerReceiver(mLocalReceiver, mFilter); } /** * 一定记得取消注册 */ @Override protected void onPause() { super.onPause(); mLocalBroadcastManager.unregisterReceiver(mLocalReceiver); } }
003.总结:
--> BroadcastReceiver里面的onReceiver()方法中不能添加过多的逻辑或者耗时操作,因为广播接收者是不允许开线程的,但是可以在里面开起服务执行耗时操作,因此广播接收者更多是扮演打开程序其他组件的角色,比如创建一条状态栏通知、启动一个服务
--> 对于不同注册方式的广播接收者回调onReceive(Context context,Intent intent)中的context返回值是不一样的:
1>.对于静态注册(全局+应用内广播),回调onReceive(context, intent)中的context返回值是:ReceiverRestrictedContext;
2>.对于全局广播的动态注册,回调onReceive(context, intent)中的context返回值是:Activity Context;
3>.对于应用内广播的动态注册(LocalBroadcastManager方式),回调onReceive(context, intent)中的context返回值是:Application Context;
4>.对于应用内广播的动态注册(非LocalBroadcastManager方式),回调onReceive(context, intent)中的context返回值是:Activity Context;
004.个人总结可能有错误,欢迎指正探讨,参照博文:
a、传送门 :优快云--细节篇,一篇就够了
b、传送门 :简书--相对比较好的一篇
Last:欢迎探讨学习