8月1日 第5章 全局大喇叭——详解广播机制(存在待续)

昨日补充

关于gradle默认使用谷歌,这使得在国内下载库等行为非常缓慢

我们进行镜像设置以加快构建速度,以下是当前可使用的腾讯云镜像

首先在gradle-wrapper.properties文件中,修改如下代码段

distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.7-bin.zip

然后在settings.gradle.kts文件中对应的代码段添加加粗代码即可

repositories {
    maven(url = "https://mirrors.cloud.tencent.com/nexus/repository/maven-public/")
    google()
    mavenCentral()
}

maven(url = "https://mirrors.cloud.tencent.com/nexus/repository/maven-public/") 

1.广播概念

标准广播:所有广播接收器都会在几乎同一时间接收到。

有序广播:同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。优先级高的广播接收器就可以先收到广播消息,并且前面的广播接收器还可以截断正在传递的广播。

2.接收广播

接收方式分为动态注册监听与静态注册监听

动态注册监听:

MainActivity中写一个内部类NetworkChangeReceiver,继承自BroadcastReceiver

//内部类
    class NetworkChangeReceiver extends BroadcastReceiver{
//接收到广播会执行的代码
        @Override
        public void onReceive(Context context, Intent intent) {
            ConnectivityManager connectionManager = (ConnectivityManager)
                    getSystemService(Context.CONNECTIVITY_SERVICE);
            //需要添加权限转AndroidManifest.xml
            NetworkInfo networkInfo = connectionManager.getActiveNetworkInfo();
            if (networkInfo != null && networkInfo.isAvailable()){
                Toast.makeText(context,"网络已连接",
                        Toast.LENGTH_SHORT).show();
            }else {
                Toast.makeText(context,"网络未连接",
                        Toast.LENGTH_SHORT).show();
            }
        }
    }

然后添加全局变量

private IntentFilter intentFilter;
private NetworkChangeReceiver networkChangeReceiver;

其中intentFilter是用来存储要接收的指定广播

networkChangeReceiver则是我们创建的内部类,用来调用内部类中的代码

onCreate()方法中:

//新建一个IntentFilter实例(意图过滤器),存入指定的广播
intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
//新建这个内部类的示例,并对这个内部类与上文的IntentFliter进行注册
networkChangeReceiver = new NetworkChangeReceiver();
registerReceiver(networkChangeReceiver,intentFilter);

动态注册广播监听器就完成了,但是还要进行解除注册

一定要写解除注册的代码

这里重写onDestroy()方法来解除注册

这个方法就是在Activity生命周期中的销毁之前调用的代码,所以可以理解为是在程序销毁时对监听器接触注册

protected void onDestroy(){
//调用父类中的onDestroy,也就是重写之前的
    super.onDestroy();
    unregisterReceiver(networkChangeReceiver);
}

注意,我们写的是监听系统网络状态的广播,这会涉及一些权限的问题

详见内部类NetworkChangeReceiver的onReceive()方法

我们需要在AndroidManifest.xml中声明权限

<!-- 添加访问系统网络权限 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

现在写出来的是监听系统网络状态的

也就是当系统网络状态发生改变时就会调用内部类中的代码

静态注册监听(待续):

前排提示:我写了出来但不知为什么无法接收到广播,如果您仔细看的话可以看到我在代码中加入了log,Toast等方式来判断广播是否发出/接收,最后发现是没有接收到,我不是很明白,目前并没有查到相关资料,所以这里比较草率简略

静态注册主要是为了让程序在未启动的情况下也能收到广播

静态注册监听需要新建Receiver类,并且继承BroadcastReceiver类

package com.example.broadcasttest;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;

public class MyBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO: This method is called when the BroadcastReceiver is receiving
        // an Intent broadcast.
        Log.d("MyBroadcastReceiver", "接收到广播");
        Toast.makeText(context, "已接收广播", Toast.LENGTH_LONG).show();
    }
}

然后在AndroidManifest.xml的<application>标签中对监测器进行注册

        <receiver
            android:name=".MyBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
<!--            接收什么广播-->
            <intent-filter>
                <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
            </intent-filter>
        </receiver>

这样我们的监听器就可以接收com.example.broadcasttest.MY_BROADCAST的广播了(不知道为什么并没有)

接下来我们写一个按钮,使点击时发送广播

Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        //创建一个广播
        Intent intent = new
                Intent("com.example.broadcasttest.MY_BROADCAST");
        //发送广播
        sendBroadcast(intent);
        Toast.makeText(MainActivity.this,"0",Toast.LENGTH_SHORT).show();
        Log.d("MainActivity", "广播已发送: " + intent.getAction());
    }
});

不知道为什么能够在log日志中找到该广播,但并不会触发接收广播的方法

然后补充接收开机的广播

<!-- 添加监听开机广播权限 -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<!-- <application>标签内-->
<!-- 静态广播接收器注册 -->
<receiver
    android:name=".BootCompleteReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
    </intent-filter>
</receiver>

有序广播:(待续)

有序广播只需要修改一些代码即可


Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        //创建一个广播
        Intent intent = new
                Intent("com.example.broadcasttest.MY_BROADCAST");
        //发送广播
        sendOrderedBroadcast(intent, null); 
        Toast.makeText(MainActivity.this,"0",Toast.LENGTH_SHORT).show();
        Log.d("MainActivity", "广播已发送: " + intent.getAction());
    }
});

 sendOrderedBroadcast(intent, null); 

如你所见我们只需要修改发送广播的代码即可

即将 sendBroadcast()方法改成sendOrderedBroadcast(intent, null);

其中null处所填的是权限相关的东西,目前不考虑

而谁最先获得广播是由优先级考虑的

<receiver 
     android:name=".MyBroadcastReceiver" 
     android:enabled="true" 
     android:exported="true"> 
     <intent-filter android:priority="100">
         <action android:name="com.example.broadcasttest.MY_BROADCAST" /> 
     </intent-filter> 
 </receiver>

android:priority="100"

是的这是在静态注册中进行设置的,优先级较高的会优先接收广播,并且可以选择阻断它

public class MyBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO: This method is called when the BroadcastReceiver is receiving
        // an Intent broadcast.
        Log.d("MyBroadcastReceiver", "接收到广播");
        Toast.makeText(context, "已接收广播", Toast.LENGTH_LONG).show();
        abortBroadcast(); 
    }
}
abortBroadcast(); 

如果在 onReceive()方法中调用了 abortBroadcast()方法,就表示将这条广播截断。

由于本书没有说动态注册监听是否可以设置优先级,所以这里暂时不做拓展

本地广播

public class MainActivity extends AppCompatActivity { 
    private IntentFilter intentFilter; 
    private LocalReceiver localReceiver;
    private LocalBroadcastManager localBroadcastManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.activity_main);
        localBroadcastManager = LocalBroadcastManager.getInstance(this); // 获取实例
        Button button = (Button) findViewById(R.id.button); 
        button.setOnClickListener(new View.OnClickListener() {
            @Override 
            public void onClick(View v) {
                Intent intent = new Intent("com.example.broadcasttest.LOCAL_BROADCAST");
                localBroadcastManager.sendBroadcast(intent); // 发送本地广播
            }
        });
        intentFilter = new IntentFilter();
        intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST"); 
        localReceiver = new LocalReceiver(); 
        localBroadcastManager.registerReceiver(localReceiver, intentFilter); // 注册本地广播监听器
    }
    @Override 
    protected void onDestroy() {
        super.onDestroy(); 
        localBroadcastManager.unregisterReceiver(localReceiver); 
    }
    class LocalReceiver extends BroadcastReceiver {
        @Override 
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "received local broadcast", Toast.LENGTH_SHORT).show();
        }
    }
}  

他和上面的动态注册监听器很像

只是通过 LocalBroadcastManager的 getInstance()方法得到了它的一个实例

注册广播接收器的时候调用的是 LocalBroadcastManager 的 registerReceiver()方法

发送广播的时候调用的是LocalBroadcastManager的sendBroadcast()方法

其余基本一样

缺点:本地广播无法通过静态注册的方式来接收

优点:

  1. 可以明确地知道正在发送的广播不会离开我们的程序,不必担心机密数据泄漏。

  2. 其他的程序无法将广播发送到我们程序的内部,不需要担心会有安全漏洞的隐患。

  3. 发送本地广播比发送系统全局广播更加高效。

  • 11
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值