Android的全局大喇叭—–详解广播机制
一, 简介
在android的广播机制中,每个程序都可以对之间感兴趣的广播内容进行注册,这样程序就只会接收到自己所关心的广播内容,这些广播可能是来自于系统的,也可能是来自于其他应用程序。Android提供了一套完整的API,允许程序自由地发送和接收广播。
发送广播的方法以前就已经有提到过,就是借助我们学过的Intent(点击链接到Intent知识点)
而接收广播的方法则需要引入一个新的概念——广播接收器(Broadcast Receiver)
二,Android中的广播分类
1.标准广播(Normal broadcasts)
标准广播是一种完全异步执行的广播,在广播发出之后所有的广播接收器机会都会在同一时间接收到这条广播信息,因此它们之间没有任何先后顺序可言。这种广播的效率会比较高,但同时也意味着它是无法被截断的。
标准广播工作示意图
2.有序广播(Ordered broadcasts)
有序广播是一种异步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够接收到这条广播信息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。所以此时的广播接收器是有先后顺序的,优先级高的广播接收器就可以先收到广播的信息,并且前面的广播接收器还可以截断在传递的广播,这样后面的广播接收器就无法收到广播信息了。
有序广播工作示意图
三, 接收系统广播
——android中内置了很多系统级别的广播,我们可以在应用程序中通过监听这些广播来得到各种系统的状态信息。比如手机开机完成后会发出一条广播,电池的电量发生变化会发出一条广播,时间或时区发生变化也会发出一条广播,等等。如果想要接收到这些广播,就需要使用广播接收器,下面我将给大家看一些具体的用法。
四,实例展示
广播接收器可以自由的对自己感兴趣的广播进行注册,这样当有相应的广播发出时,广播接收器就能够接收到该广播,并在内部处理相应的逻辑。注册广播的方式一般有两种,在代码中注册和在AndroidManifest.xml中注册,其中前者也被称为动态注册,后者也被称为静态注册。
1.接收广播——动态注册监听网络变化
新建并继承BroadcastReceiver的类
package com.example.gq.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.os.NetworkOnMainThreadException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private NetworkChangeReceiver networkChangeReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intentFilter = new IntentFilter();
//创建intentFileter的实例
intentFilter.addAction("android.net.conn.CONNECTIVTY_CHANGE");
/*
给IntentFilter添加一个android.net.conn.CONNECTIVTY_CHANGE的action的action
因为当系统的网络状态发生改变时,系统就会发出一条android.net.conn.CONNECTIVTY_CHANGE
的广播,也就是说我们的广播接收器想要监听什么样的广播,就在这里添加对应的action
*/
networkChangeReceiver=new NetworkChangeReceiver();
//创建NetworkChangeReceiver的实例
registerReceiver(networkChangeReceiver,intentFilter);
//调用registerReceiver方法进行注册
/*
用registerReceiver方法将intentFileter实例注册为广播接收器:
registerReceiver方法将NetworkChangeReceiver的实例和IntertFilter的实例都
传递进去,这样NetworlChangeReceiver就会收到所有值为android.net.conn.CONNECTITY_CHANGE的
广播,这样大致就实现了监听网络变化的功能
*/
}
@Override
protected void onDestroy(){
super.onDestroy();
unregisterReceiver(networkChangeReceiver);
/*
动态注册的广播接收器一定都要取消注册才行
在这里我们在onDestroy()方法中通过调用unregisterReceiver()方法来实现的。
*/
}
class NetworkChangeReceiver extends BroadcastReceiver{
/*NetworkChangeReceiver 继承BroadcastReceiver类,并重写父类BroadcastReceiver的
* onReceive方法,这样每当网络状态发生改变时OnReceive()的方法会得到执行
* 就是简单的使用Toast提示一段文本信息
*/
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"network changes",Toast.LENGTH_SHORT).show();
//下面是附加一些方法来提高程序的精准性,准确告诉用户当前是有网络还是无网络
ConnectivityManager connectivityManager=(ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
/*
在onRecceive()方法中,首先通过getSystemBervice()方法得到ConnectivityManager的实例
这是一个系统服务类,专门用于管理网络连接的,然后调用它的getActiveNetworkInfo()方法
可以得到NetworlInfo的实例,接着调用NetworkInfo的isAvailable()方法,判断当前是否有网络
最后我们还是通过Toast的方式对用户进行提示。
提示:
安卓系统为了保护用户设备的安全和隐私,做了严格的规定:
如果程序需要进行一些对用户来说比较敏感的操作,就必须在配置文件中声明权限才可以,
否则程序将会直接崩溃。
在此的访问系统网络权限是需要声明权限的,打开AndroidManifest.xml文件,在里面加入如下权限
就可以访问系统权限了:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
*/
NetworkInfo networkInfo=connectivityManager.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();
}
}
}
}
/*
整体代码如上,但是需要注意的就是运行程序。
首先我们会在注册完成的时候,收到一条广播,然后按下Home键回到主界面
(注意不能按Back键,否则就会执行onDestroy()方法,即取消注册)
然后自己再设置中更改网络状态
这时就会看到Toasy提醒你的网络状态发生变化
*/
这里有一点需要说明,Android系统为了保护用户设备的安全和隐私,做了严格的规定:如果程序需要进行一些对用户来说比较敏感的操作,就必须在配置文件中声明权限才可以,否则程序就会直接崩溃(是不是现在说一经崩溃一次了 (・ω・)/(ノД`゚)゚ 哈哈,让我们赶紧添加上权限声明吧!)
AndroidManifest,xml文件中添加权限声明
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.gq.broadcasttest">
//权限声明
<!--下面是有关动态广播的系统网络权限获取-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--下面是有关静态广播的系统网络权限声明-->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
//活动声明
<application
android: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>
//静态广播声明
<receiver
android:name=".BootCompleteReceiver"
android:enabled="true"
android:exported="true">
<!--上面两行是创建广播文件的时候,自己选择自动生成的两个属性!-->
<!--第一行:enabled属性是表示是否启用这个广播接收器-->
<!--第二行:exported属性是表示是否允许这个广播接收器接收本程序以外的广播-->
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<!--由于android系统启动完成后会发出一条值为:android.intent.action.BOOT_COMPLETED的广播-->
<!--因此我们在<ibtebt-filter>标签里添加了相应的action-->
</intent-filter>
</receiver>
</application>
</manifest>
看到这里是不是吓一跳,别急其实代码没有这么多。
这里我将全部的Androidmanifest.xml文件中的代码全部贴上来了,也包括我们马上要讲的静态注册广播接收器。
其实我们这里需要做权限声明的代码就只有一行,那就是下面有关动态权限声明的代码:
<!--下面是有关动态广播的系统网络权限获取-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
是不是很简单?
其实我们接下来要讲的静态注册更加简单!
2.接收广播——静态注册监听网络变化
动态注册的广播接收器可以自由地控制注册于注销,在灵活性方面有很大的优势,但是它也存在着一个缺点,即必须要在程序启动之后才能接收到广播,因为注册的逻辑是写在onReceive()方法里执行相应的逻辑,从而实现开机启动的功能。
静态注册广播接收器的方法
使用Android Studio提供的快捷方式来创建一个广播接收器,右击com.example.(自己创建的后缀)包—>New—>Other—>Broad Receiver,会弹出创建广播接收器的窗口。
在Class Name:中输入广播接收器的名字。
Exported属性表示是否允许这个广播接收器接收本程序以外的广播
Enabled属性表示是否启用这个广播接收器。
这里我们两个属性都进行勾选,点击Finish完成创建,然后修改刚刚创建类的代码。
package com.example.gq.broadcasttest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class BootCompleteReceiver extends BroadcastReceiver {
@Override
public 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_LONG).show();
}
}
这里我们只是早onReceive( )方法中使用Toast弹出一段提示信息。
另外静态广播接收器一定要在AndroidManifest.xml文件中注册才可以使用,不过我们是使用的Android Studio的快捷方式创建的广播接收器,因此注册这一步已经被自动完成了。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.gq.broadcasttest">
//权限声明
<!--下面是有关动态广播的系统网络权限获取-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--下面是有关静态广播的系统网络权限声明-->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
//活动声明
<application
android: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>
//静态广播声明
<receiver
android:name=".BootCompleteReceiver"
android:enabled="true"
android:exported="true">
<!--上面两行是创建广播文件的时候,自己选择自动生成的两个属性!-->
<!--第一行:enabled属性是表示是否启用这个广播接收器-->
<!--第二行:exported属性是表示是否允许这个广播接收器接收本程序以外的广播-->
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<!--由于android系统启动完成后会发出一条值为:android.intent.action.BOOT_COMPLETED的广播-->
<!--因此我们在<ibtebt-filter>标签里添加了相应的action-->
</intent-filter>
</receiver>
</application>
</manifest>
后期我们还需要加上相应的代码,例如静态注册的权限声明,响应广播的活动声明,这样我们就完成了一次静态监听手机开机的广播接收器了。
注意!!!
<>
最后提醒大家一点的是,我们在广播接收器的onReceive( )方法中都只是简单地使用Toast提示了一段文本消息。当我们在真正的项目中用到它的时候,就可以在其中编写自己的逻辑。
不过不要在onReceive( )方法中添加过多的逻辑或者进行任何耗时的操作。因为在广播接收器中是允许开启线程的,当onReceive( )方法运行了较长的时间而没有结束时,程序就会报错。
因此,广播接收器更多的是扮演一种打来程序其他组件的角色1,比如创建一条状态栏通知,或者创建启动一个服务等。
这次晚这么多。。。
开启一个完整的项目,但是由于人家是白纸一张。
还有许多东西要学,进度缓慢。。。
还是和往常一样,给大家推荐一些歌!
I’ll Be Missing You
Star Sky - Instrumental
加油吧!!!ヾ( ̄□ ̄)ノ