Android学习笔记之——Broadcast机制

之前的博文中已经较为详细的介绍了activity机制,本博文来看看broadcast机制。

 

目录

广播的简介

接收系统广播

动态注册监听网络变化

静态注册实现开机启动


 

广播的简介

为了便于进行系统级别的消息通知,Android也引入了一套类似的广播消息机制——broadcast。broadcast简单地响应从其他应用程序或者系统发来的广播消息。Android中的每个应用程序都可以对自己感兴趣的广播进行注册,这样该程序就只会接收到自己所关心的广播内容,这些广播可能是来自于系统的,也可能是来自于其他应用程序的。Android提供了一套完整的API,允许应用程序自由地发送和接收广播。发送广播的方法就是之前博文《Android学习笔记之——通过Intent来实现Activity之间数据传递 》中提到的intent,而接收广播的方法则是广播接收机(Broadcast Receiver)。

Android中的广播主要可以分为两种类型:标准广播和有序广播。

  1. 标准广播 (Normal broadcasts)是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因此它们之间没有任何先后顺序可言。这种广播的效率会比较高,但同时也意味着它是无法被截断的。如下图所示。
    标准广播
  2. 有序广播 (Ordered broadcasts)则是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。所以此时的广播接收器是有先后顺序的,优先级高的广播接收器就可以先收到广播消息,并且前面的广播接收器还可以截断正在传递的广播,这样后面的广播接收器就无法收到广播消息了。如下图所示。
    有序广播

接收系统广播

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

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

动态注册监听网络变化

通过新建一个类,让它继承自BroadcastReceiver ,并重写父类的onReceive() 方法就可以创建一个广播接收器了。当有广播到来时,onReceive() 方法就会得到执行,具体的逻辑就可以在这个方法中处理。新建一个BroadcastTest项目

然后修改MainActivity中的代码,如下所示:

package com.example.broadcasttest;

import androidx.appcompat.app.AppCompatActivity;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private IntentFilter intentFilter;
    //IntentFilter主要用来过滤隐式意图
    // 当用户进行一项操作的时候,Android系统会根据配置的 “意图过滤器” 来寻找可以响应该操作的组件,服务。

    private NetworkChangeReceiver networkChangeReceiver;

    //定义一个一个类,让它继承自BroadcastReceiver
    // 并重写父类的onReceive() 方法,以此创建一个广播接收器
    class NetworkChangeReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            //采用Toast来发送消息
            Toast.makeText(context, "network changes", Toast.LENGTH_SHORT).show();
            //通过静态方法makeText() 创建出一个Toast对象
            //并通过show()将Toast显示出来
            // makeText() 方法需要传入3个参数。
            // 第一个参数是Context ,也就是Toast要求的上下文,活动本身就是一个Context 对象。
            // 第二个参数是Toast显示的文本内容,
            // 第三个参数是Toast显示的时长,有两个内置常量可以选择Toast.LENGTH_SHORT 和Toast.LENGTH_LONG

        }
    }


    //完成该activity各种初始化操作,如加载布局、绑定事件等
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //Intent所传递的信息
        intentFilter=new IntentFilter();//首先创建一个IntentFilter 的实例
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");//给其添加一个action
        //当网络的状态发生变化时,系统所发出的,正是上面名称的广播

        //广播接收器
        networkChangeReceiver = new NetworkChangeReceiver();//创建了一个NetworkChangeReceiver 的实例
        registerReceiver(networkChangeReceiver, intentFilter);
        //调用registerReceiver() 方法进行注册
        //将NetworkChangeReceiver 的实例和IntentFilter的实例(即上面的信息)都传了进去
    }

    //动态注册的广播接收器一定都要取消注册
    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(networkChangeReceiver);
        //通过调用unregisterReceiver() 方法来实现networkChangeReceiver广播的取消注册
    }

}

运行一下程序。首先你会在注册完成的时候收到一条广播,然后按下Home键回到主界面(注意不能按Back键,否则onDestroy() 方法会执行),接着打开Settings程序→Data usage进入到数据使用详情界面,然后尝试着开关Cellular data按钮来启动和禁用网络,你就会看到有Toast提醒你网络发生了变化。

进一步地,对上述代码进行修改,修改为具体说明网络是有还是无,修改如下:

package com.example.broadcasttest;

import androidx.appcompat.app.AppCompatActivity;

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.Bundle;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private IntentFilter intentFilter;
    //IntentFilter主要用来过滤隐式意图
    // 当用户进行一项操作的时候,Android系统会根据配置的 “意图过滤器” 来寻找可以响应该操作的组件,服务。

    private NetworkChangeReceiver networkChangeReceiver;

    //定义一个一个类,让它继承自BroadcastReceiver
    // 并重写父类的onReceive() 方法,以此创建一个广播接收器
    class NetworkChangeReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
//            //采用Toast来发送消息
//            Toast.makeText(context, "network changes", Toast.LENGTH_SHORT).show();
//            //通过静态方法makeText() 创建出一个Toast对象
//            //并通过show()将Toast显示出来
//            // makeText() 方法需要传入3个参数。
//            // 第一个参数是Context ,也就是Toast要求的上下文,活动本身就是一个Context 对象。
//            // 第二个参数是Toast显示的文本内容,
//            // 第三个参数是Toast显示的时长,有两个内置常量可以选择Toast.LENGTH_SHORT 和Toast.LENGTH_LONG

            
            ConnectivityManager connectionManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
            //首先通过getSystemService() 方法得到了ConnectivityManager 的实例
            //这是一个系统服务类,专门用于管理网络连接的

            NetworkInfo networkInfo = connectionManager.getActiveNetworkInfo();
            //调用getActiveNetworkInfo() 方法可以得到NetworkInfo 的实例
            if (networkInfo != null && networkInfo.isAvailable()) { //NetworkInfo 的isAvailable() 方法,就可以判断出当前是否有网络
                Toast.makeText(context, "network is available",Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(context, "network is unavailable",Toast.LENGTH_SHORT).show();
            }

        }
    }


    //完成该activity各种初始化操作,如加载布局、绑定事件等
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //Intent所传递的信息
        intentFilter=new IntentFilter();//首先创建一个IntentFilter 的实例
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");//给其添加一个action
        //当网络的状态发生变化时,系统所发出的,正是上面名称的广播

        //广播接收器
        networkChangeReceiver = new NetworkChangeReceiver();//创建了一个NetworkChangeReceiver 的实例
        registerReceiver(networkChangeReceiver, intentFilter);
        //调用registerReceiver() 方法进行注册
        //将NetworkChangeReceiver 的实例和IntentFilter的实例(即上面的信息)都传了进去
    }

    //动态注册的广播接收器一定都要取消注册
    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(networkChangeReceiver);
        //通过调用unregisterReceiver() 方法来实现networkChangeReceiver广播的取消注册
    }

}

由于Android系统为了保护用户设备的安全和隐私,做了严格的规定:如果程序需要进行一些对用户来说比较敏感的操作,就必须在配置文件中声明权限才可以,否则程序将会直接崩溃。比如这里访问系统的网络状态就是需要声明权限的。打开AndroidManifest.xml文件,在里面加入如下权限就可以访问系统网络状态了:

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

但是打开后发现已经存在了(再次感觉android studio便捷)

静态注册实现开机启动

动态注册的广播接收器可以自由地控制注册与注销,在灵活性方面有很大的优势。但是由于注册的逻辑是写在onCreate()方法中的,因此需要启动程序才可以接收到广播。

此处,让程序接收一条开机广播,当收到这条广播时就可以在onReceive() 方法里执行相应的逻辑,从而实现开机启动的功能。可以使用Android Studio提供的快捷方式来创建一个广播接收器,右击com.example.broadcasttest包→New→Other→Broadcast Receiver,会弹出如下图所示的窗口。

  • Exported 属性表示是否允许这个广播接收器接收本程序以外的广播
  • Enabled 属性表示是否启用这个广播接收器

然后修改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 {

    @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();
    }
}

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

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

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

<?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.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">
        <receiver
            android:name=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

值得注意的是:不要在onReceive() 方法中添加过多的逻辑或者进行任何的耗时操作,因为在广播接收器中是不允许开启线程的,当onReceive() 方法运行了较长时间而没有结束时,程序就会报错。因此广播接收器更多的是扮演一种打开程序其他组件的角色,比如创建一条状态栏通知,或者启动一个服务等。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Broadcast 广播是 Android 系统中的一种重要的组件通信方式,它可以让应用程序之间进行消息传递,从而实现应用程序之间的数据交换和功能协同。广播可以被用来处理一些系统事件或应用程序内部的特定事件。在本篇文章中,我们将学习如何在 Android 应用程序中使用广播。 一、广播的基本概念 广播是指一种可以跨应用程序发送和接收消息的机制,它允许应用程序向全局范围内的其他应用程序通知某些事件的发生。Android 中的广播可以分为两类: 1.标准广播(Normal Broadcast):这种广播是完全异步的,所有的接收者都会在同一时刻接收到广播消息,因此它们之间没有任何优先级的区别。使用标准广播时,所有接收者都无法终止广播的传播,这也是标准广播的一个缺点。 2.有序广播(Ordered Broadcast):这种广播是同步执行的,所有的接收者都是按照优先级顺序依次接收广播消息的。在广播传递过程中,每个接收者都可以截断广播的传播,使得后面的接收者无法收到广播消息。如果某个接收者截断了广播的传播,那么其后面的接收者就无法收到广播消息。这种广播的优先级由高到低依次为:1000、500、0、-500、-1000。 二、发送和接收广播 1.发送广播 在 Android 应用程序中,我们可以通过以下代码来发送广播: ```java Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST"); sendBroadcast(intent); ``` 上述代码中,我们首先创建了一个 Intent 对象,然后将其 action 设置为 "com.example.broadcasttest.MY_BROADCAST",这个 action 可以自己定义。最后,我们调用了 sendBroadcast() 方法来发送广播。 2.接收广播 要接收广播,需要在代码中注册一个 BroadcastReceiver 对象,并在其 onReceive() 方法中处理广播消息。以下是一个简单的例子: ```java public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "Received in MyBroadcastReceiver", Toast.LENGTH_SHORT).show(); } } ``` 在上述代码中,我们创建了一个 MyBroadcastReceiver 类,并实现了其 onReceive() 方法。当收到广播消息时,系统会自动调用该方法,并将广播消息以 Intent 对象的形式传递给该方法。在 onReceive() 方法中,我们可以根据 Intent 对象中携带的信息来进行相应的处理,例如弹出一个 Toast 提示框。 3.注册广播接收器 在 Android 应用程序中,我们需要使用 IntentFilter 对象来指定要接收的广播类型。以下是一个注册广播接收器的例子: ```java MyBroadcastReceiver receiver = new MyBroadcastReceiver(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction("com.example.broadcasttest.MY_BROADCAST"); registerReceiver(receiver, intentFilter); ``` 在上述代码中,我们首先创建了一个 MyBroadcastReceiver 对象,然后创建了一个 IntentFilter 对象,并将要接收的广播类型设置为 "com.example.broadcasttest.MY_BROADCAST"。最后,我们调用 registerReceiver() 方法来注册广播接收器。 4.注销广播接收器 当我们不再需要接收某个广播时,应该及时将其注册的广播接收器进行注销。以下是一个注销广播接收器的例子: ```java unregisterReceiver(receiver); ``` 在上述代码中,我们调用 unregisterReceiver() 方法来注销广播接收器。 三、有序广播的使用 有序广播可以让我们按照优先级顺序接收广播消息,并且可以截断广播的传播。以下是一个有序广播的例子: ```java Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST"); sendOrderedBroadcast(intent, null); ``` 在上述代码中,我们调用了 sendOrderedBroadcast() 方法来发送有序广播。由于没有指定接收者的权限,因此我们将其设置为 null。 接下来,我们需要在代码中注册一个 BroadcastReceiver 对象,并在其 onReceive() 方法中处理广播消息。以下是一个简单的例子: ```java public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String msg = getResultData(); Toast.makeText(context, msg + " Received in MyBroadcastReceiver", Toast.LENGTH_SHORT).show(); setResultData("Hello MainActivity"); } } ``` 在上述代码中,我们首先调用 getResultData() 方法来获取上一个接收者设置的数据,然后弹出一个 Toast 提示框,并将自己的数据设置为 "Hello MainActivity"。 接下来,我们需要指定广播接收者的优先级。在 AndroidManifest.xml 文件中,我们可以使用 priority 属性来设置广播接收者的优先级。以下是一个简单的例子: ```xml <receiver android:name=".MyBroadcastReceiver"> <intent-filter> <action android:name="com.example.broadcasttest.MY_BROADCAST"/> </intent-filter> <priority android:priority="1000" /> </receiver> ``` 在上述代码中,我们将 MyBroadcastReceiver 类注册为广播接收者,并将其优先级设置为 1000。 为了演示有序广播的效果,我们可以再注册一个 BroadcastReceiver 对象,并将其优先级设置为 500。以下是一个简单的例子: ```java public class AnotherBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String msg = getResultData(); Toast.makeText(context, msg + " Received in AnotherBroadcastReceiver", Toast.LENGTH_SHORT).show(); setResultData("Hello MainActivity"); } } ``` 在上述代码中,我们将 AnotherBroadcastReceiver 类注册为广播接收者,并将其优先级设置为 500。 最后,我们在 AndroidManifest.xml 文件中注册这两个广播接收者,代码如下: ```xml <receiver android:name=".MyBroadcastReceiver"> <intent-filter> <action android:name="com.example.broadcasttest.MY_BROADCAST"/> </intent-filter> <priority android:priority="1000" /> </receiver> <receiver android:name=".AnotherBroadcastReceiver"> <intent-filter> <action android:name="com.example.broadcasttest.MY_BROADCAST"/> </intent-filter> <priority android:priority="500" /> </receiver> ``` 在上述代码中,我们将 MyBroadcastReceiver 和 AnotherBroadcastReceiver 类都注册为广播接收者,并指定了它们的优先级。 在执行上述代码后,我们可以看到,在发送广播时,首先会将广播消息发送给优先级为 1000 的 MyBroadcastReceiver 类,然后再发送给优先级为 500 的 AnotherBroadcastReceiver 类。在 MyBroadcastReceiver 类的 onReceive() 方法中,我们可以获取到 AnotherBroadcastReceiver 类设置的数据,然后弹出一个 Toast 提示框,并将自己的数据设置为 "Hello MainActivity"。最后,我们可以看到,弹出的 Toast 提示框中显示的内容为 "Hello MainActivity Received in MyBroadcastReceiver",这表明 MyBroadcastReceiver 类成功地截断了广播的传播。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值