Android 内置了很多系统级别的广播,我们可以在应用程序中通过监听这些广播来得到 各种系统的状态信息。比如手机开机完成后会发出一条广播,电池的电量发生变化会发出一 条广播,时间或时区发生改变也会发出一条广播等等。如果想要接收到这些广播,就需要使 用广播接收器,下面我们就来看一下它的具体用法。

5.2.1    动态注册监听网络变化

广播接收器可以自由地对自己感兴趣的广播进行注册,这样当有相应的广播发出时,广 播接收器就能够收到该广播,并在内部处理相应的逻辑。注册广播的方式一般有两种,在代 码中注册和在 AndroidManifest.xml 中注册,其中前者也被称为动态注册,后者也被称为静态 注册。

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

那我们就先通过动态注册的方式编写一个能够监听网络变化的程序,借此学习一下广播 接收器的基本用法吧。新建一个 BroadcastTest 项目,然后修改 MainActivity 中的代码,如下 所示:

public class MainActivity extends Activity {

private IntentFilter intentFilter;

private NetworkChangeReceiver networkChangeReceiver;

@Override

protected void
onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); 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 {

@Override

public void onReceive(Context context, Intent intent) {

Toast.makeText(context,
"network changes", Toast.LENGTH_SHORT).show();

}

}

}

可以看到,我们在 MainActivity 中定义了一个内部类 NetworkChangeReceiver,这个类 是继承自 BroadcastReceiver 的,并重写了父类的 onReceive()方法。这样每当网络状态发生变 化时,onReceive()方法就会得到执行,这里只是简单地使用 Toast 提示了一段文本信息。

然后观察 onCreate()方法,首先我们创建了一个 IntentFilter 的实例,并给它添加了一个 值为 android.net.conn.CONNECTIVITY_CHANGE 的 action,为什么要添加这个值呢?因为 当网络状态发生变化时,系统发出的正是一条值为 android.net.conn.CONNECTIVITY_ CHANGE 的广播,也就是说我们的广播接收器想要监听什么广播,就在这里添加相应的 action 就行了。接下来创建了一个 NetworkChangeReceiver 的实例,然后调用 registerReceiver() 方法进行注册,将 NetworkChangeReceiver 的实例和
IntentFilter 的实例都传了进去,这样 NetworkChangeReceiver 就会收到所有值为 android.net.conn.CONNECTIVITY_CHANGE 的广 播,也就实现了监听网络变化的功能。

最后要记得,动态注册的广播接收器一定都要取消注册才行,这里我们是在 onDestroy()方法中通过调用 unregisterReceiver()方法来实现的。 整体来说,代码还是非常简单的,现在运行一下程序。首先你会在注册完成的时候收到一条广播,然后按下 Home 键回到主界面(注意不能按 Back 键,否则 onDestroy()方法会执 行),接着按下 Menu
键→System settings→Data usage 进入到数据使用详情界面,然后尝试着 开关 Mobile
Data 来启动和禁用网络,你就会看到有 Toast
提醒你网络发生了变化。

不过只是提醒网络发生了变化还不够人性化,最好是能准确地告诉用户当前是有网络还
是没有网络,因此我们还需要对上面的代码进行进一步的优化。修改 MainActivity 中的代码, 如下所示:

public class MainActivity extends
Activity {

……

class NetworkChangeReceiver extends
BroadcastReceiver {

@Override

public 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()方法中,首先通过 getSystemService()方法得到了 ConnectivityManager 的 实例,这是一个系统服务类,专门用于管理网络连接的。然后调用它getActiveNetworkInfo() 方法可以得到 NetworkInfo 的实例,接着调用 NetworkInfo 的 isAvailable()方法,就可以判断 出当前是否有网络了,最后我们还是通过 Toast
的方式对用户进行提示。

另外,这里有非常重要的一点需要说明,Android 系统为了保证应用程序的安全性做了 规定,如果程序需要访问一些系统的关键性信息,必须在配置文件中声明权限才可以,否则
程 序 将 会 直 接 崩 溃 , 比 如 这 里 查 询 系 统 的 网 络 状 态 就 是 需 要 声 明 权 限 的 。 打 开 AndroidManifest.xml 文件,在里面加入如下权限就可以查询系统网络状态了:

<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.broadcasttest"

android:versionCode="1" android:versionName="1.0"
>

<uses-sdk
android:minSdkVersion="14" android:targetSdkVersion="19"
/>

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

……

</manifest>

访问 http://developer.android.com/reference/android/Manifest.permission.html可以查看 Android

系统所有可声明的权限。

现在重新运行程序,然后按下 Home 键→按下 Menu
键→System settings→Data usage 进 入到数据使用详情界面,关闭 Mobile Data 会弹出无网络可用的提示,如图 5.3 所示。

图   5.3

然后重新打开 Mobile
Data 又会弹出网络可用的提示,如图 5.4 所示。

图   5.4

5.2.2    静态注册实现开机启动

动态注册的广播接收器可以自由地控制注册与注销,在灵活性方面有很大的优势,但是 它也存在着一个缺点,即必须要在程序启动之后才能接收到广播,因为注册的逻辑是写在 onCreate()方法中的。那么有没有什么办法可以让程序在未启动的情况下就能接收到广播 呢?这就需要使用静态注册的方式了。

这里我们准备让程序接收一条开机广播,当收到这条广播时就可以在 onReceive()方法里 执行相应的逻辑,从而实现开机启动的功能。新建一个 BootCompleteReceiver 继承自 BroadcastReceiver,代码如下所示:

public class BootCompleteReceiver extends BroadcastReceiver {

@Override

public void onReceive(Context context, Intent intent) { Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show();

}

}

可以看到,这里不再使用内部类的方式来定义广播接收器,因为稍后我们需要在 AndroidManifest.xml 中将这个广播接收器的类名注册进去。在 onReceive()方法中,还是简单 地使用 Toast 弹出一段提示信息。

然后修改 AndroidManifest.xml 文件,代码如下所示:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.broadcasttest"

android:versionCode="1" android:versionName="1.0" >

……

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" >

……

<receiver android:name=".BootCompleteReceiver" >

<intent-filter>

<action android:name="android.intent.action.BOOT_COMPLETED" />

</intent-filter>

</receiver>

</application>

</manifest>

终于,<application>标签内出现了一个新的标签<receiver>,所有静态注册的广播接收器
都是在这里进行注册的。它的用法其实和<activity>标签非常相似,首先通过 android:name 来指定具体注册哪一个广播接收器,然后在<intent-filter>标签里加入想要接收的广播就行了, 由于 Android 系统启动完成后会发出一条值为 android.intent.action.BOOT_COMPLETED 的广 播,因此我们在这里添加了相应的 action。

另外,监听系统开机广播也是需要声明权限的,可以看到,我们使用<uses-permission>标签又加入了一条 android.permission.RECEIVE_BOOT_COMPLETED 权限。 现在重新运行程序后,我们的程序就已经可以接收开机广播了,首先打开到应用程序管理界面来查看一下当前程序所拥有的权限。在桌面按下 Menu 键→System settings→Apps,然 后点击 BroadcastTest,如图 5.5
所示。

图   5.5

可以看到,我们的程序目前拥有访问网络状态和开机自动启动的权限。然后将模拟器关
闭并重新启动,在启动完成之后就会收到开机广播了,如图 5.6 所示。

图   5.6

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

android: 接收系统广播的更多相关文章

  1. Android 接收系统广播(动态和静态)

    1.标准广播:是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎会在同一时刻接收到这条广播信息,它们之间没有先后顺序.效率高.无法被截断. 2.有序广播:是一种同步执行的广播,在广播发出后 ...

  2. Android接收系统广播

    Android内置了很多系统级别的广播,我们可以在应用程序中通过监听这些广播来得到各种系统的状态信息.比如手机开机完成后会发出一条广播,电池的电量发生变化会发出一条广播,时间或时区发生改变也会发出一条 ...

  3. Android开发之接收系统广播消息

    BroadcastReceiver除了接收用户所发送的广播消息之外.另一个重要的用途:接收系统广播. 假设应用须要在系统特定时刻运行某些操作,就能够通过监听系统广播来实现.Android的大量系统事件 ...

  4. android接收短信——framework处理流程(android 5.1)

    modem层不懂,所以直接从RIL.java开始.以电信卡接收短信为例 modem通知RIL.java中的 RILReceiver处理接收信息 class RILReceiver implements ...

  5. Android接收短信

    Android收到短信时会广播android.provider.Telephony.SMS_RECEIVED消息,因此只要定义一个Receiver,收听该消息,就能接收短信. <receiver ...

  6. android: 接收和发送短信

    8.2    接收和发送短信 收发短信应该是每个手机最基本的功能之一了,即使是许多年前的老手机也都会具备这 项功能,而 Android 作为出色的智能手机操作系统,自然也少不了在这方面的支持.每个 A ...

  7. Android常用系统广播

    关于Intent的使用,可参阅前章:http://www.cnblogs.com/caidupingblogs/p/5101669.html //关闭或打开飞行模式时的广播 Intent.ACTION ...

  8. Android 接收短信

    启动程序时启动一个service,在service里注册接收短信的广播,当手机收到短信里,打印出短信内容跟电话号码. package com.lmy.SmsListener; import andro ...

  9. Android接收wifi路由器发送过来的一组字节数据

    1.字节数组转换为字符串 byte[] byBuffer = new byte[20];... ...String strRead = new String(byBuffer);strRead = S ...

随机推荐

  1. 【ES】match_phrase与regexp

    刚开始接触es,由于弄不清楚match_phrase和regexp导致很多查询结果与预想的不同.在这整理一下. regexp:针对的是单个词项 match_phrase:针对的是多个词项的相对位置 它 ...

  2. 保存 laravel model 而不更新 timestamps 的方法

    $product = Product::find(1); $product->view_count += 1; $product->timestamps = false; $product ...

  3. 洛谷p1072 gcd,质因数分解

    /* 可以得a>=c,b<=d,枚举d的质因子p 那么a,b,c,d,x中包含的p个数是ma,mb,mc,md,mx 在gcd(a,x)=c中 ma<mc => 无解 ma=m ...

  4. ie7 下 float换行问题与vertical-align:middle; 失效问题

    声明:web小白的笔记,欢迎大神指点!联系QQ:1522025433. ie7 下 float换行问题 请直接看代码中和代码中的注释: <!doctype html> <html&g ...

  5. web中切图、快速切图与web雪碧图制作的方法

    声明: web小白的笔记,欢迎大神指点,联系QQ:1522025433. 工具:Photoshop 1.复制文字:点击文章工具后选择文字. 2.矩形选框工具 看信息 f8, 取消矩形选框 Ctrl+D ...

  6. div展开与收起(鼠标点击)

    效果图: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...

  7. jqgrid 表格中筛选条件的多选下拉,树形下拉 ;文本框清除插件;高级查询多条件动态筛选插件[自主开发]

    /** * @@desc 文本框清除按钮,如果isAutoWrap为false当前文本框父级必须是relative定位,boostrap参考input-group * @@author Bear.Ti ...

  8. #13【BZOJ2794】[Poi2012]Cloakroom

    题解: 感觉真是很智障..连这么简单的题都没想出来 一直在想这么做动态背包..发现不会 首先显然我们将询问按照m 序列按照a[i]排序 然后怎么满足b呢 其实很简单啊..只需要记录f[i]表示前面这些 ...

  9. 注册表键值明明存在OpenSubKey始终返回null,解决方案

    先上代码及实例 RegistryKey rsg = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Macromedia\FlashPaper Pri ...

  10. 【AtCoder】CODE FESTIVAL 2017 qual B

    最近不知道为啥被安利了饥荒,但是不能再玩物丧志了,不能颓了 饥荒真好玩 A - XXFESTIVAL CCFESTIVAL #include <bits/stdc++.h> #define ...