Android 第十九课 大喇叭--广播机制----动态注册监听网络变化与静态注册实现开机启动

为了便于进行 系统级别的消息通知,Android引入了一套广播消息机制。
1、广播机制简介:
因为Android中的每个应用程序都可以对自己感兴趣的广播尽心注册,这样程序只会接收自己所关心的广播内容,
这些广播来自于系统的,也可能来自于其他应用程序的。Android提供了一套完整的API,允许应用程序自己地发送和
接收广播,发送广播的方法就是借助Intent,而接收广播的方法,要引入广播接收器(Broadcast Receiver)。

广播分为两类,标准广播和有序广播,
标准广播(Normal broadcase)是一种完全异步执行的广播,再广播发出去以后,
所有的广播接收器机会会在同一时刻接收到这条广播消息,因此它们之间没有任何先后顺序,这样的广播的效率会比较高
但同时也意味着它是无法被截断的。‘
有序广播(Ordered broadcasts)是一种同步执行的广播,在广播发出去之后,同一时刻只会有一个广播接收器能
够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。优先级高的广播就可以先接收广播消息,并且还可以截断正在传递的广播。


二、接收系统广播
Android内置了很多系统级别的广播,我们可以在应用程序中通过监听这些广播来得到各种系统的状态信息。
1、动态注册监听网络变化
广播接收器可以自由的对自己感兴趣的广播进行注册,当有相应的广播发出时,广播接收器就可以收到该广播,并在
内部处理相应的逻辑。
注册广播的方式一般有两种 ,动态注册和静态注册,所谓动态注册是在代码中注册,静态注册在
AndroidManifest.xml中注册。

如何创建一个广播接收器呢? 只需要新建一个类,让它继承自BroadcastReceiver,并重写父类的onReceive()方法
就行了。这样当有广播到来时, onReceive()方法就会得到执行,具体的逻辑就会在这个方法中处理。


我们先通过 动态注册的方式去编写一个能够监听网络变化的程序,学习一下广播接收器的基本用法。
新建项目BroadcastTest。然后,修改MainActivity中的代码:
package com.example.broadcasttest;


import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;


public class MainActivity extends AppCompatActivity {
    
    
    private IntentFilter intentfiletr;

    private NetworkChangeReceiver networkChangeReceiver;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        intentfiletr = new IntentFilter();
        intentfiletr.addAction("android.net.conn.CONNECTIVITY_CHANGE");

        networkChangeReceiver = new NetworkChangeReceiver();
        registerReceiver(networkChangeReceiver,intentfiletr);

    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(networkChangeReceiver);
    }



    class NetworkChangeReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context,"network changes",Toast.LENGTH_SHORT).show();
        }
    }

}
我们在MainActivity中定义了一个内部类 NetworkChangeReceiver,这个类是继承自BroadcastReceiver的,并重写了
父类的 onReceive()这样每当网络状态发生变化时,onReceive()方法都会得到执行,这里只是简单的使用Toast提示了一段文本信息
在onCreat()方法,我们首先创建了一个IntenFilter的实例,并给它添加了一个android.net.conn.CONNECTIVITY_CHANGE的
广播,也就是说当我们想要监听什么样的广播,就在这里添加相应的action。接下来,我们创建一个NetworkChangeReceiver
的实例,然后调用registerReceiver()方法进行注册,将NetworkChangeReciver的实例和IntentFilter的实例都传了进去
这样,NetworkChangeReceiver就会收到所有值为android.conn.CONNECTIVITY_CHANGE的广播。也就实现了监听网络
变化的功能。
最后,动态注册的广播接收器一定要取消注册才行。我们是在onDestroy()方法中通过调用unregisterReceiver()来实现。


总结:
如何创建一个广播接收器呢?广播接收器如何接收广播呢?
1、只需要新建一个类,让它继承自BroadcastReceiver,并重写父类的onReceive()方法
就行了。这样当有广播到来时,onReceiver方法就会得到执行,具体的逻辑就会在这个方法中处理。然后创建这个类的
实例,调用其registerReceive()方法进行注册,最后也可以在onDestroy()方法取消注册。
2、发送广播的方法是借助Intent。怎么接收广播呢?通过创建一个IntentFilter的实例,往里面添加相应的action,
就可以接收对应的广播。


运行代码之后,,在注册完成的时候,会收到一条广播,然后按下Home键,回到主页面,接着打开Setting程序->
Data usage 进入到数据使用详情界面,然后尝试着开关Cellular data 按钮来启动和禁用网络,看到有Toast提醒网络
发生了变化。
最后可以准确告诉用户当前是有网络还是无网络,我们进一步优化代码:
package com.example.broadcasttest;import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;public class MainActivity extends AppCompatActivity {private IntentFilter intentfiletr;private NetworkChangeReceiver networkChangeReceiver;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);intentfiletr = new IntentFilter();intentfiletr.addAction("android.net.conn.CONNECTIVITY_CHANGE");networkChangeReceiver = new NetworkChangeReceiver();registerReceiver(networkChangeReceiver,intentfiletr);}@Overrideprotected void onDestroy() {super.onDestroy();unregisterReceiver(networkChangeReceiver);}class NetworkChangeReceiver extends BroadcastReceiver{@Overridepublic void onReceive(Context context, Intent intent) {
ConnectivityManager connectionManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);NetworkInfo networkInfo = connectionManager.getActiveNetworkInfo();if(networkInfo != null && networkInfo.isAvailable()){Toast.makeText(context,"network is available",Toast.LENGTH_SHORT).show();}else{Toast.makeText(context,"network is unavailable",Toast.LENGTH_SHORT).show();}}}
}


在onReceive方法中,首先通过getSystemSerive()方法得到ConnectivityManager的实例,这是一个系统服务类,专门
用来管理网络连接的。然后调用它的getAcitiveNetworkInfo()方法得到NetworkInfo的实例,接着调用NetworkInfo的
isAvailable()方法,就可以判断当前是否有网络了,最后我们还是通过Toast的方式对用户进行提示。
Android系统为了保护用户设备的安全和隐私,做了严格的规定,如何程序需要做一些对用户来说比较敏感的操作,就必须在
配置文件中声明权限才可以,否则程序将会直接崩溃。打开AndroidManifest.xml文件,在下面加入如下权限就可以访问
系统网络状态了:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcasttest">


    ......
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
......
</manifest>
Android有很多操作都是需要声明权限才可以进行的。
现在我们又可以重新运行程序了。




2、静态注册实现开机启动

动态注册的广播接收器可以自由地控制注册与注销,有很大的灵活性,但有一个缺点,必须要在程序启动之后才能接收广播,因为注册的逻辑是写在onCreate()方法中的,可以采取静态注册的方式,让程序在未启动的情况下接收到广播;

我们让程序接收一条开机广播,当收到这条广播时就可以在onReceive()方法里执行相应的逻辑,从而实现开机启动的功能。我们右击com.example.broadcasttest包,-->New->another-->Broadcast Receiver,将这个广播接收器命名为BootCompleteReceiver,Exported属性表示是否允许广播接收器接收本程序以外的广播,Enabled属性表示是否启用这个广播接收器。勾选这两个属性,点击Finish完成创建。

然后修改BootCompleteReceiver中的代码,如下:

package com.example.broadcasttest;import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;public class BootCompleteReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {// TODO: This method is called when the BroadcastReceiver is receiving// an Intent broadcast.Toast.makeText(context,"Boot Complete",Toast.LENGTH_SHORT).show();}
}

代码很简单,只是在onReceiver()方法中使用Toast弹出一段提示信息。

另外静态的广播接收器一定要在AndroidManifest.xml文件中注册才可以使用,不过由于我们使用的是Android Studio的快捷方式创建的广播接收器,因此注册这一步已经被自动完成了。代开AndroidManifest.xml文件看一看,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.broadcasttest"><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><receiverandroid:name=".BootCompleteReceiver"android:enabled="true"android:exported="true"></receiver></application></manifest>

可以看到在,<application>标签内出现了一个新的标签<receiver>所有静态的广播接收器都是在这里进行注册的。她的用法其实和<activity>标签非常相似,也是通过android:name来指定注册具体哪一个广播接收器,而enabled和exported属性则是根据我们刚才勾选的状态自动生成的。

不过目前BootCompleteReceiver还是不能接收到开机广播的,我们还需要对AndroidManifest.xml文件进行修改才行,如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.broadcasttest"><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permission android:name = "android.permision.RECEIVE_BOOT_COMPLETED"/><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><receiverandroid:name=".BootCompleteReceiver"android:enabled="true"android:exported="true"><intent-filter><action android:name="android.intent.action.BOOT_COMPLETED"/></intent-filter></receiver></application></manifest>

由于Android系统启动完成后会发出一条值为android.intent.action.BOOT_COMPLETED的广播,因此我们在<intent-filter>标签里添加了相应的action。另外监听系统开机广播也是需要权限的,可以看到,我们使用<uses-permission>标签又加入了一条android.permission.RECEIVE_BOOT_COMPLETED权限。

我们重新运行程序之后,就可以接收开机广播了。

我们在广播接收器中的onReceive()方法都只是简单的使用Toast提示了一段文本信息,当你真正在项目中使用到它的时候,就可以在里面编写自己的逻辑。不要在onReceive()方法中添加过多的逻辑或者进行任何的耗时操作,因为在广播接收器中式不允许开启线程的,当onReceive()方法运行了较长时间还没有结束时,程序就会报错。因此广播接收器更多的扮演一种打开程序或其他组件的角色,比如创建一条状态栏通知,或者启动一个服务等。

















本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/274087.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

dbus 和 policykit 实例篇(python)

dbus 和 policykit 实例篇&#xff08;python&#xff09; 使用policykit 的程序一般都有一个dbus daemon程序来完成相关操作&#xff0c;这个dbus daemon 会在系统注册一个system bus 服务名&#xff0c;用于响应要求root privileged的操作&#xff0c;当dbus请求到达时会先验…

一个实际的sonar代码检查的配置文件

国内私募机构九鼎控股打造APP&#xff0c;来就送 20元现金领取地址&#xff1a;http://jdb.jiudingcapital.com/phone.html内部邀请码&#xff1a;C8E245J &#xff08;不写邀请码&#xff0c;没有现金送&#xff09;国内私募机构九鼎控股打造&#xff0c;九鼎投资是在全国股份…

JavaScript 第二课 JavaScript语法

本章内容&#xff1a;语句变量和数组操作符条件语句和循环语句函数与对象 ------------------------------------------------------------- 准备&#xff1a; 编写JavaScript脚本只需要一个普通地文本编辑器和一个Web浏览器就足啦。 用JavaScript编写的代码必须通过HTML/XHTML…

和菜鸟一起学linux之DBUS基础学习记录

转自&#xff1a;http://blog.csdn.net/eastmoon502136/article/details/10044993 D-Bus三层架构 D-Bus是一个为应用程序间通信的消息总线系统, 用于进程之间的通信。它是个3层架构的IPC 系统&#xff0c;包括&#xff1a; 1、函数库libdbus &#xff0c;用于两个应用程序互…

Android 第二十课 广播机制(大喇叭)----发送自定义广播(包括发送标准广播和发送有序广播)

广播分为两种类型&#xff1a;标准广播和有序广播 我们来看一下具体这两者的具体区别&#xff1a; 1、发送标准广播 我们需要先定义一个广播接收器来准备接收此广播才行&#xff0c;否则也是白发。 新建一个MyBroadcastReceiver,代码如下&#xff1a; package com.example.broa…

八大排序算法

概述 排序有内部排序和外部排序&#xff0c;内部排序是数据记录在内存中进行排序&#xff0c;而外部排序是因排序的数据很大&#xff0c;一次不能容纳全部的排序记录&#xff0c;在排序过程中需要访问外存。 我们这里说说八大排序就是内部排序。 当n较大&#xff0c;则应采用…

需求?

1 需求怎样描述清楚&#xff1f; 利用用例技术&#xff0c;一般这里指的是系统用例&#xff1b;包括以下几个内容&#xff1a; 用例视图 系统的功能描述&#xff1b; 用例规约 规定了用户和系统的交互过程&#xff1b;用户如何使用系统&#xff1b;用户如何交互&#xff0c;以及…

Android 第二十一课 RecyclerView简单的应用之编写“精美”的聊天页面

1、由于我们会使用到RecyclerView&#xff0c;因此首先需要在app/build.gradle当中添加依赖库。如下&#xff1a; apply plugin: com.android.application .... dependencies {....compile com.android.support:recyclerview-v7:26.1.0 } 2、然后开始编写主页面&#xff0c;修该…

VS 2008 生成操作中各个选项的差别

近日&#xff0c;在编译C#项目时经常发现有些时候明明代码没错&#xff0c;但就是编译不过&#xff0c;只有选择重新编译或者清理再编译才会不出错&#xff0c;本着求学的态度&#xff0c;搜罗了下VS2008IDE中生成操作的种类以及差别&#xff0c;整理如下&#xff1a;内容(Cont…

dbus-python指南

菜鸟学dbus-python&#xff0c;翻译dbus-python指南&#xff0c;错误之处请在所难免&#xff0c;请诸位不吝赐教&#xff0c;多多指正&#xff01;查看英文原版请点这里。 连接总线Connecting to the Bus方法调用Making method calls代理对象proxy objects接口和方法Interfaces…

JavaScript 第三课 DOM

主要内容&#xff1a; 节点5个常用的DOM方法&#xff1a;getElementById、getElementByTagname、getElementByClassName、getAttribute和setAttribute详细内容: 1、文档&#xff1a;DOM中的“D”如果没有document(文档),DOM也就无从谈起。当创建了一个网页并把它加载到Web浏览器…

源码编译安装Nginx

1.源码下载 Nginx在github上有一个只读源码库&#xff0c;我获取的源码方式为&#xff1a; git clone https://github.com/nginx/nginx.git 2.configure 我下载源码的时候&#xff0c;github上的源码的目录结构为: auto, conf, contrib, docs, misc, src共6个目录。src目录是…

SOAP协议初级指南(2)

目前的技术存在的问题&#xff1f;   尽管DCOM和IIOP都是固定的协议&#xff0c;业界还没有完全转向其中任何一个协议。没有融合的部分原因是文化的问题所致。而且在当一些组织试图标准化一个或另一个协议的时候&#xff0c;两个协议的技术适用性就被提出质疑。传统上认为DC…

JavaScript 第四课 案例研究:JavaScript图片库

主要内容&#xff1a;编写一个优秀的标记文件编写一个JavaScript函数以显示用户想要查看的内容由标记出发函数调用使用几个新方法扩展这个JavaScript函数 学习过DOM&#xff0c;我们用JavaScript和DOM去建立一个图片库。最好的办法是什么呢&#xff1f; 利用JavaScript来建立图…

windows下mongodb安装与使用整理

一、首先安装mongodb 1.下载地址&#xff1a;http://www.mongodb.org/downloads 2.解压缩到自己想要安装的目录&#xff0c;比如d:\mongodb 3.创建文件夹d:\mongodb\data\db、d:\mongodb\data\log&#xff0c;分别用来安装db和日志文件&#xff0c;在log文件夹下创建一个日志文…

可变参数列表(va_list,va_arg,va_copy,va_start,va_end)

本文转自:http://blog.csdn.net/costa100/article/details/5787068 va_list arg_ptr&#xff1a;定义一个指向个数可变的参数列表指针&#xff1b;      va_start(arg_ptr, argN)&#xff1a;使参数列表指针arg_ptr指向函数参数列表中的第一个可选参数&#xff0c;说明&…

src与href属性的区别

src和href之间存在区别&#xff0c;能混淆使用。src用于替换当前元素&#xff0c;href用于在当前文档和引用资源之间确立联系。 src是source的缩写&#xff0c;指向外部资源的位置&#xff0c;指向的内容将会嵌入到文档中当前标签所在位置&#xff1b;在请求src资源时会将其指向…

USACO4.12Beef McNuggets(背包+数论)

昨天晚上写的一题 结果USACO一直挂中 今天交了下 有一点点的数论知识 背包很好想 就是不好确定上界 官方题解&#xff1a; 这是一个背包问题。一般使用动态规划求解。 一种具体的实现是&#xff1a;用一个线性表储存所有的节点是否可以相加得到的状态&#xff0c;然后每次可以…

Java 循环语句中 break,continue,return有什么区别?

break 结束循环&#xff0c;跳出循环体,进行后面的程序;continue 结束本次循环&#xff0c;进行下次循环;return 跳出循环体所在的方法&#xff0c;相当于结束该方法; 例子&#xff1a; public class whiletrueTest{public static void main(String[] args) {heihei();haha();…

Epoll模型详解

转自http://blog.163.com/huchengsz126/blog/static/73483745201181824629285/ Linux 2.6内核中提高网络I/O性能的新方法-epoll I/O多路复用技术在比较多的TCP网络服务器中有使用&#xff0c;即比较多的用到select函数。 1、为什么select落后 首先&#xff0c;在Linux内核中…