Android学习笔记-Broadcast01-详解广播机制

Posted 双木青橙

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android学习笔记-Broadcast01-详解广播机制相关的知识,希望对你有一定的参考价值。

前言

广播是一个消息通知机制,android提供了一套完整的API,允许应用程序自由地发送和接收广播。就是我们常说的Android 四大组件之一的广播接收器(Broadcast Receiver).

广播机制说明

  • 广播类型
    广播常分为两种类型,标准广播(Normal broadcasts)是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都在会同一时间收到这条广播消息,之间也没有任何先后顺序可言,并且也无法被截断。
    有序广播(Ordered broadcasts)则是一个同步执行的广播,在广播发出之后,同一时刻只有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。并且前面的广播接收器还可以截断正在传递的广播
  • 动态广播与静态广播
    动态广播是通过代码在Acvitity启动之后通过代码来注册与注销的。比较灵活,在实际开发中一般也推荐这种
    但是静态广播是可以在程序未启动时就可以收到广播

示例

示例1- 动态广播监听系统网络变化

广播其实不单可以监听到APP内的广播,同时也可以监听到系统和其他应用发来的广播,如下示例就是通过动态注册的方式监听系统网络变化
接收器是需要继承BroadcastReceiver 并重写onReceive()方法

package com.example.boardcasttest;

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.view.View;
import android.widget.Button;
import android.widget.Toast;

import java.util.logging.Logger;

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);
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(v -> 
            Intent intent = new Intent("com.example.boardcasttest.MY_BROADCAST");
            sendBroadcast(intent);
        );
        intentFilter = new IntentFilter();
        //想要监听什么广播,在每个地方添加相应的action
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        networkChangeReceiver = new NetworkChangeReceiver();
        // 注册广播
        registerReceiver(networkChangeReceiver, intentFilter);
    

    @Override
    protected void onDestroy() 
        super.onDestroy();

        // 注销广播
        unregisterReceiver(networkChangeReceiver);
    

    /**
     * 网络变化广播接收器
     *
     * @author huanglin
     * @since 2021/7/18
     */
    class NetworkChangeReceiver extends BroadcastReceiver 
        @Override
        public void onReceive(Context context, Intent intent) 
            ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
            // 获取网络信息
            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();
            

        
    

访问系统的网络状态是需要声明权限的,在AndroidManifest.xml加入相应权限即可

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.boardcasttest">

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

示例2- 静态注册实现开机启动

静态广播可以在程序未启动时就能接收到广播,如下所示,我们在AndroidMenifest.xml定义相应拦截信息并自定义一个对应的广播接收器
到目前为止,我们在广播接收器中的onReceive()方法都是简单使用Toast,真正使用时则可以在里面添加自己的业务逻辑。但是,**不要在onReceive()方法中添加过多的逻辑或者进行任何的耗时操作,因为在广播接收器中是不允许开线程的,当onReceive()方法运行了较长时间而没有结束时,程序就会报错。

/**
 * 开机启动广播接收器
 *
 * @author huanglin
 * @since 2021/7/18
 */
public class BootCompleteReceiver extends BroadcastReceiver 

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

AndroidManifest定义相应权限及拦截filter

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

    <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/Theme.BoardcastTest">
        <receiver
            android:name=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <!--系统启动完成发送的广播-->
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
    </application>
</manifest>

示例3-发送自定义广播

广播又称为无序(标准)广播和无序广播,他们的区别前面已经介绍,他们的启动方法如下所示:
标准广播通过sendBroadcast()来发送广播,而有序广播则是通过sendOrderedBroadcast()来发送广播,并且有序广播需要指定优先级并区分接收器收到广播的优先级
创建MyBroadcastReceiver去接收广播

public class MyBroadcastReceiver extends BroadcastReceiver 

    @Override
    public void onReceive(Context context, Intent intent) 
        Toast.makeText(context,"received in MyBoardcastReceiver",Toast.LENGTH_SHORT).show();
        // 中止广播
        abortBroadcast();
    

并在AndroidManifest.xml增加对其的MY_BROADCAST广播的接收,并设置优先级为100,保证一定比AnotherBroadcastReceiver先收到广播

        <receiver
            android:name=".MyBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter android:priority="100">
                <action android:name="com.example.boardcasttest.MY_BROADCAST" />
            </intent-filter>
        </receiver>
```java
创建另一个BroadcastTest2 项目,新建一个AnotherBroadcastReceiver 去接收广播
```java
/**
 * 另一个广播接收器
 *
 * @author huanglin
 * @since 2021/7/18
 */
public class AnotherBroadcastReceiver extends BroadcastReceiver 

    @Override
    public void onReceive(Context context, Intent intent) 
        Toast.makeText(context, "received in Another BroadcastReceiver", Toast.LENGTH_SHORT).show();
    

并AndroidManifest.xml项目中进行增加对于MY_BROADCAST的广播拦截

        <receiver
            android:name=".AnotherBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
            </intent-filter>
        </receiver>
 需要注意的是,上面发送和接收的广播全部属于系统全局广播,**即发出的广播可以被其他任何应用程序接收到**,并且我们也可以接收到来自其他程序的广播。这样很容易引起安全性的问题,比如我们改送一些携带关键性数据的广播有可能被其他的应用程序截获,或者其他的程序不停地向我们的广播接收器发送各种垃圾广播。
 为了能够简单地解决广播的安全性问题,Android引入了一套本地广播机制。具体请参考下一节学习笔记

参考资料

《第一行代码Android(第2版)》

以上是关于Android学习笔记-Broadcast01-详解广播机制的主要内容,如果未能解决你的问题,请参考以下文章

Android学习笔记-Broadcast01-详解广播机制

android学习笔记

Android安全笔记-Broadcast基本概念

数学建模学习笔记(二十九)BP神经网络使用详例

Android学习总结——Broadcast

Android开发学习之路--Broadcast Receiver初体验