10、广播接收器(Broadcast Receiver)
Android 中的广播主要可以分为两种类型,标准广播和有序广播。
标准广播(Normal broadcasts):
是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因此它们之间没有任何先后顺序可言
有序广播(Ordered broadcasts):
是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。所以此时的广播接收器是有先后顺序的,优先级高的广播接收器就可以先收到广播消息,并且前面的广播接收器还可以截断正在传递的广播
注册广播的方式一般有两种,在代码中注册和在 AndroidManifest.xml 中注册,其中前者也被称为动态注册,后者也被称为静态注册。
创建一个广播接收器:
新建一个类,让它继承自 BroadcastReceiver,并重写父类的 onReceive()方法就行了。这样当有广播到来时,onReceive()方法就会得到执行
动态注册:
因为逻辑都是写在onCreate()中,所以必须要在程序启动之后才能接收到广播
动态注册的广播接收器一定都要取消注册才行,这里我们是在 onDestroy()方法中通过调用 unregisterReceiver()方法来实现的
class NetworkChangeReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "network changes",Toast.LENGTH_SHORT).show(); } }
//MainActivity: protected void onCreate(Bundle savedInstanceState) { ... //当网络状态发生变化时,系统发出的正是一条值为 android.net.conn.CONNECTIVITY_CHANGE 的广播 intentFilter = new IntentFilter(); intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE"); //接收器 networkChangeReceiver = new NetworkChangeReceiver(); registerReceiver(networkChangeReceiver, intentFilter); } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(networkChangeReceiver); } class NetworkChangeReceiver extends BroadcastReceiver { }
打 开AndroidManifest.xml 文件,在里面加入如下权限
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
静态注册:
可以让程序在未启动的情况下就能接收到广播
新建一个 BootCompleteReceiver 继承自BroadcastReceiver:
public class BootCompleteReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show(); } }
在 AndroidManifest.xml中添加:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <application …… <receiver android:name=".BootCompleteReceiver" > <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver> </application>
发送自定义广播
发送标准广播:
1、新建一个广播接收器
新建一个 MyBroadcastReceiver继承自 BroadcastReceiver
2、在 AndroidManifest.xml 中对这个广播接收器进行注册
<receiver android:name=".MyBroadcastReceiver"> <intent-filter> <action android:name="com.example.broadcasttest.MY_BROADCAST"/> </intent-filter> </receiver>
3、定义按钮发送广播
public void onClick(View v) { Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST"); sendBroadcast(intent); }
发送有序广播:
1~2跟标准广播一样
4、
Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST"); sendOrderedBroadcast(intent, null);
sendOrderedBroadcast()方法接收两个参数,第一个参数仍然是Intent,第二个参数是一个与权限相关的字符串,这里传入 null 就行了
android:priority 属性给广播接收器设置了优先级,优先级比较高的广播接收器就可以先收到广播
<receiver android:name=".MyBroadcastReceiver"> <intent-filter android:priority="100" > <action android:name="com.example.broadcasttest.MY_BROADCAST"/> </intent-filter> </receiver>
abortBroadcast()方法,就表示将这条广播截断,在广播接收器中使用
使用本地广播:
前面我们发送和接收的广播全部都是属于系统全局广播,
即发出的广播可以被其他任何的任何应用程序接收到,并且我们也可以接收来自于其他任何应用程序的广播
本地广播的用法并不复杂,主要就是使用了一个 LocalBroadcastManager 来对广播进行管理
1、接收器
class LocalReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "received local broadcast",Toast.LENGTH_SHORT).show(); } }
2、
public class MainActivity extends Activity { private IntentFilter intentFilter; private LocalReceiver localReceiver; private LocalBroadcastManager localBroadcastManager; @Override protected void onCreate(Bundle savedInstanceState) { 。。。 //获取localBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this); Button button = (Button) findViewById(R.id.button); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // 发送本地广播 Intent intent = new Intent("com.example.broadcasttest.LOCAL_BROADCAST"); localBroadcastManager.sendBroadcast(intent); } }); intentFilter = new IntentFilter(); intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST"); localReceiver = new LocalReceiver(); localBroadcastManager.registerReceiver(localReceiver, intentFilter); } @Override protected void onDestroy() { super.onDestroy(); localBroadcastManager.unregisterReceiver(localReceiver); }
广播的最佳实践——实现强制下线功能
原理:
点击强制下线按钮,发送一条”强制下线“的广播,在广播接收器里弹出一个不可取消的对话框,点击对话框确定按钮,调用 ActivityCollector 的 finishAll()方法来销毁掉所有活动,并重新启动 LoginActivity 这个活动
强制用户下线的逻辑并不是写在 MainActivity 里的,而是应该写在接收这条广播的广播接收器里面,这样强制下线的功能就不会依附于任何的界面,不管是在程序的任何地方,只需要发出这样一条广播,就可以完成强制下线的操作了。
注意:
由于我们是在广播接收器里启动活动的,因此一定要给Intent 加入 FLAG_ACTIVITY_NEW_TASK 这个标志。
还需要把对话框的类型设为 TYPE_SYSTEM_ALERT,不然它将无法在广播接收器里弹出
1、发送广播:
public void onClick(View v) { Intent intent = new Intent("com.example.broadcastbestpractice.FORCE_OFFLINE "); sendBroadcast(intent); }
2、接收广播:
public class ForceOfflineReceiver extends BroadcastReceiver { @Override public void onReceive(final Context context, Intent intent) { Toast.makeText(context, "received in ForceOfflineReceiver", Toast.LENGTH_SHORT).show(); AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context); dialogBuilder.setTitle("Warning"); dialogBuilder.setMessage("You are forced to be offline. Please try to login again."); dialogBuilder.setCancelable(false); //点击对话框OK dialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { ActivityCollector.finishAll(); // 销毁所有活动 Intent intent = new Intent(context,MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); // 重新启动LoginActivity } }); AlertDialog alertDialog = dialogBuilder.create(); // 需要设置AlertDialog的类型,保证在广播接收器中可以正常弹出 alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_TOAST); alertDialog.show(); // context.unregisterReceiver(this); } }
3、注册广播接收器,声明权限 android.permission.SYSTEM_ALERT_WINDOW
问题:
1、Broadcast的onReceive方法中弹出AlertDialog
使用静态注册广播,只能弹出System Alert类型的Dialog。但google在 6.0加入了运行时权限的概念,需要在java代码中进行动态申请。为了防止旧的应用程序崩溃,只对targetSDK为23及以上的程序使用新的权限机制。
相应的解决方法有如下几种。
第一种方式是:targetSDK设为23以下就可以规避问题。
第二种方式是:设置里面给了这个调试应用【允许悬浮窗】 但是得手动的打开(我是没有找到这个悬浮窗到底在哪里)。
第三种方式是:使用无需权限显示悬浮窗。
a 修改广播接收类中的import包 将
import android.support.v7.app.AlertDialog;
修改为:
import android.app.AlertDialog;
b 修改AlertDialog的弹窗类型为:TYPE_TOAST 将
alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
修改为:
alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_TOAST);
这样编译运行就可以正常弹出AlertDialog了。
2、在广播中弹出对话框与在Activiity中弹出对话框有所不同,在Activiity中弹出对话框,我们需要用到当前Activiity的Context,而在广播中并没有,如果一定要在广播中弹出一个对话框,我需要定义这个对话框是一个系统级别的。
首先需要有弹出系统对话框的权限
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
在show()之前,要先设置Dialog的类型为TYPE_SYSTEM_ALERT。
alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
最后,最最重要的,AlertDialog要使用android.app.AlertDialog,不要用v7包下的Dialog,会报错。
相关推荐
【标题】"第一行代码Android学习练习代码9" 涉及的是Android开发中的实践环节,这通常是基于郭文静的畅销书《第一行代码——Android》中的第九个练习项目。这本书是Android初学者入门的经典教材,通过实际的编程练习...
《第一行Android代码(第二版)》是一本深入浅出的Android编程入门书籍,它旨在帮助初学者快速理解和掌握Android应用开发的基本技能。书中通过丰富的实例和详细的解释,引导读者从零开始,逐步构建自己的第一个...
《第一行代码-Android 源代码》是郭霖撰写的一本面向初学者的Android编程书籍,这本书通过实例引导读者逐步了解和掌握Android应用开发。源代码压缩包提供了书中所有示例程序的完整代码,方便读者实践和学习。以下是...
1. **Android Studio入门**:Android Studio是Android开发的官方集成开发环境(IDE),书中会介绍如何下载、安装和配置Android Studio,以及创建第一个"Hello, World!"应用。 2. **AndroidManifest.xml**:每个...
《Android第一行代码笔记》是针对初学者的Android开发指南,涵盖了从基础知识到实际应用的全方位内容。在学习Android开发的过程中,"第一行代码"往往代表着编程旅程的起点,这本笔记将帮助读者逐步理解并掌握这个...
《第一行代码Android学习练习代码》是针对初学者的一个实践项目,主要涵盖了Android应用开发的基础知识。这个压缩包中的"DYHDM_02_00ActivityTest"很可能是一个示例程序,用于演示和练习Android中的Activity管理。...
### 第一行代码笔记知识点梳理 #### 一、打印与日志输出 1. **`System.out.print()`**:这是Java中的标准输出方法,用于在控制台打印文本信息。 2. **`Log`类的使用**: - `v`:表示最详细的日志输出等级,通常...
本书《第一行代码——Android(第2版)》是一本适合Android初学者的教材,它详细介绍了Android开发的基础知识和技能。为了帮助读者更好地学习和掌握Android开发,书中特别为读者制定了一个四周的阅读计划,旨在通过...
《第二行代码》是一本专注于Android开发的书籍,旨在帮助开发者深入理解并掌握Android应用程序的构建技巧。书中通过丰富的实例和详细的解释,让读者能够从基础到进阶逐步提升自己的编程技能。源代码是学习过程中的...
《第一行代码——Android(第3版)》是一本专门为初学者准备的Android开发教程书籍,由郭霖编写。它以通俗易懂的语言和丰富的实例,带领初学者入门Android开发,并且循序渐进地深入到Android平台的各个方面。思维...
《第一行Android代码》课件:第五章 全局大喇叭-详解广播机制.pptx
《Android第二行代码》是一本深受开发者欢迎的Android编程入门书籍,其全书源代码包含了大量的实例和练习,旨在帮助读者深入理解Android应用开发的基本概念和技术。这些源代码覆盖了从基础到进阶的各种主题,涵盖了...
【标题】"第一行代码Java源代码第12章课程代码Java网络编"涉及的是Java编程语言在网络编程方面的知识,这是Java开发中的一个重要领域。在这一章节中,开发者通常会学习如何利用Java API来实现网络通信,包括客户端与...
发送自定义广播的逻辑: 1.构建一个Intent对象,并将要发送的广播的值传入,2.调用Intent的setPackage()方法,并传入当前应用程序的包名。3.最后调用sendBroadcast 发送广播。 //首先构造了一个Intent对象,将要...
《Android第二行代码》是Android开发领域的一本经典著作,主要面向初级到中级的开发者,旨在帮助他们深入理解Android应用开发。源码Demo是书中的重要组成部分,通过实践这些示例,读者可以更好地掌握Android编程的...
《第一行代码》是郭霖撰写的一本针对Android开发的入门书籍,深受初学者和有一定经验的开发者喜爱。书中的代码实例涵盖了Android开发的多个重要方面,包括UI设计、数据存储、网络通信、多媒体处理等。这个压缩包文件...
"Android第一行代码源码 BroadcastBestPractice.rar"是一个关于Android广播最佳实践的压缩包,它可能包含了详细的示例代码和讲解,旨在帮助开发者理解并掌握如何有效地使用Android广播。在这里,我们将深入探讨...
”表明这是一个与构建网络电台相关的代码资源包,里面包含了大量广播电台的数据和对应的网页实现代码。这可能是用于创建一个聚合了众多广播频道的在线平台,使得用户可以通过网站收听来自全球各地的广播节目。 描述...
在Android开发领域,"第一行代码"是一本非常受欢迎的入门书籍,由郭霖老师撰写。这本书通过实际的示例代码帮助初学者快速理解和掌握Android编程的基础知识。在这个"第一行代码(2)"的基本实现中,我们可以看到作者...