Android 获取网络连接状态新方法

2023-11-08

一. 问题背景

        Android12上,有的app模块判断当前网络的类型和连接状态时,还是使用的旧的API,导致返回的结果不准确,影响代码逻辑判断,本篇文章就这一问题,整理一下判断网络类型和连接状态的新方法。

二. 原因分析

        在Android 10以前的版本,大家都是通过NetworkInfo.java 的getType()方法获取网络类型,通过isConnected()方法来判断是否连接上, 判断网络连接的旧方法如下:

1.是否连接:

 2. 网络类型

 但是在Android10之后,这些方法已过时,官方不推荐使用,我们先来看下官方的源码说明

 左边是Android10,右边是Android9的源码 ,   在10上已经标记Deprecated,新加的注释也推荐了使用的API

还有一个旧广播String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"  Android 9之后也废弃,不推荐使用,之前的使用方法:

看下官方说明:

 官方标记Deprecated,是避免在高版本的设备上获取返回的网络状态不对,并且给了推荐的API,以Android10为一个分界点, 之后的版本都推荐使用新的API方法。

三. 官方推荐API

官方推荐:监控 Android 中的互联网连接,可以使用ConnectivityManager类,这是一个允许您查询网络状态的系统服务类,   还有一个NetworkCapabilities类,代表活动网络的功能。

体使用方法如下:

registerNetworkCallback():此函数注册一个NetworkCallback对象来监听网络状态变化。它以一个NetworkCallback对象作为参数。

unregisterNetworkCallback():此函数取消注册以前注册的NetworkCallback对象。

接下来重点关注NetworkCallback中的回调方法描述

回调方法

描述

onCapabilitiesChanged

当网络状态改变时回调,比如信号强度切换,或者连接上网络—>断开网络,或者 mobile网络切换到Wifi网络,都会回调

onAvailable

网络连接成功 但不能判断该网络是否可以正常上网

onUnavailable

当网络连接超时或网络请求达不到可用要求时调用

onBlockedStatusChanged

当访问指定的网络被阻止或解除阻塞时调用

onLosing

当网络正在断开连接时调用

onLost

当网络已断开连接时调用

onLinkPropertiesChanged

当网络连接的属性被修改时调用

接下来再说一下

NetworkCapabilities.java类中的NET_CAPABILITY_VALIDATED字段,描述为:

表示此网络上的连接已成功验证。例如,对于具有NET_CAPABILITY_INTERNET的网络,这意味着已成功检测到INTERNET连接。

通过实际log来描述说明一下:

1. 连接上可上网的wifi,可看到VALIDATED的标记:

2. 连接上需要认证和不能上网的wifi,找不到VALIDATED标记:

 3. 用数据流量上网,可以看到VALIDATED的标记:

我们可以通过networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)这个方法作为(连接可以正常上网的网络)判断条件。进一步通过networkCapabilities.hasTransport方法来判断当前的网络类型。

四. 使用方法

看代码更直接一点:

MainActivity.java

@SuppressLint("NewApi")
public class MainActivity extends AppCompatActivity {

    private static final String TAG = "ConnectManager";

    private ConnectivityManager networkService;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        networkService = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (networkService != null) {
            //注册 NetworkCallBack
            networkService.registerDefaultNetworkCallback(networkCallBack);
        }
    }


    /*
    * 测试网络工具类方法
    * */
    @Override
    protected void onResume() {
        super.onResume();
        //Log.e(TAG,  "=====在onResume方法中判断 : isMobileNetwork :" + NetworkUtils.isMobileNetwork(this));
        //Log.e(TAG,  "=====在onResume方法中判断 : isWifiNetwork :" + NetworkUtils.isWifiNetwork(this));
        //Log.e(TAG,  "=====在onResume方法中判断 : getConnectedNetworkType :" + NetworkUtils.getConnectedNetworkType(this));
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (networkService != null && networkCallBack != null) {
            networkService.unregisterNetworkCallback(networkCallBack);
        }
    }

    private final ConnectivityManager.NetworkCallback networkCallBack = new ConnectivityManager.NetworkCallback(){
        //当网络状态修改但仍旧是可用状态时调用
        @Override
        public void onCapabilitiesChanged(@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
            super.onCapabilitiesChanged(network, networkCapabilities);
            if (NetworkUtils.isConnectedAvailableNetwork(getBaseContext())) {
                Log.d(TAG, "onCapabilitiesChanged ---> ====网络可正常上网===网络类型为: "+ NetworkUtils.getConnectedNetworkType(MainActivity.this));
            }

            //表明此网络连接验证成功
            if(networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
                if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
                    Log.d(TAG, "===当前在使用Mobile流量上网===");
                } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
                    Log.d(TAG, "====当前在使用WiFi上网===");
                } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH)) {
                    Log.d(TAG, "=====当前使用蓝牙上网=====");
                } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
                    Log.d(TAG, "=====当前使用以太网上网=====");
                } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
                    Log.d(TAG, "===当前使用VPN上网====");
                } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI_AWARE)) {
                    Log.d(TAG, "===表示此网络使用Wi-Fi感知传输====");
                } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_LOWPAN)) {
                    Log.d(TAG, "=====表示此网络使用LoWPAN传输=====");
                } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_USB)) {
                    Log.d(TAG, "=====表示此网络使用USB传输=====");
                }
            }


        }

        @Override
        public void onAvailable(@NonNull Network network) {
            super.onAvailable(network);
            Log.e(TAG, "==网络连接成功,通知可以使用的时候调用====onAvailable===");
        }

        @Override
        public void onUnavailable() {
            Log.e(TAG, "==当网络连接超时或网络请求达不到可用要求时调用====onUnavailable===");
            super.onUnavailable();
        }

        @Override
        public void onBlockedStatusChanged(@NonNull Network network, boolean blocked) {
            Log.e(TAG, "==当访问指定的网络被阻止或解除阻塞时调用===onBlockedStatusChanged==");
            super.onBlockedStatusChanged(network, blocked);
        }

        @Override
        public void onLosing(@NonNull Network network, int maxMsToLive) {
            Log.e(TAG, "==当网络正在断开连接时调用===onLosing===");
            super.onLosing(network, maxMsToLive);
        }

        @Override
        public void onLost(@NonNull Network network) {
            Log.e(TAG, "==当网络已断开连接时调用===onLost===");
            super.onLost(network);
        }


        @Override
        public void onLinkPropertiesChanged(@NonNull Network network, @NonNull LinkProperties linkProperties) {
            Log.e(TAG, "==当网络连接的属性被修改时调用===onLinkPropertiesChanged===");
            super.onLinkPropertiesChanged(network, linkProperties);
        }
    };

}

网络工具类NetworkUtils.java

@SuppressLint("NewApi")
public class NetworkUtils {

    private static final String TAG = "ConnectManager";

    /**
     * Indicates this network uses a Cellular transport.
     */
    public static final int TRANSPORT_CELLULAR = 0;

    /**
     * Indicates this network uses a Wi-Fi transport.
     */
    public static final int TRANSPORT_WIFI = 1;

    /**
     * Indicates this network uses a Bluetooth transport.
     */
    public static final int TRANSPORT_BLUETOOTH = 2;

    /**
     * Indicates this network uses an Ethernet transport.
     */
    public static final int TRANSPORT_ETHERNET = 3;

    /**
     * Indicates this network uses a VPN transport.
     */
    public static final int TRANSPORT_VPN = 4;

    /**
     * Indicates this network uses a Wi-Fi Aware transport.
     */
    public static final int TRANSPORT_WIFI_AWARE = 5;

    /**
     * Indicates this network uses a LoWPAN transport.
     */
    public static final int TRANSPORT_LOWPAN = 6;

    /**
     * Indicates this network uses a Test-only virtual interface as a transport.
     * @hide
     */
    public static final int TRANSPORT_TEST = 7;

    /**
     * Indicates this network uses a USB transport.
     */
    public static final int TRANSPORT_USB = 8;



    /**
     * >= Android 10(Q版本)推荐
     *
     * 当前使用MOBILE流量上网
     */
    public static boolean isMobileNetwork(Context context) {
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);

        Network network = cm.getActiveNetwork();
        if (null == network) {
            return false;
        }

        NetworkCapabilities capabilities = cm.getNetworkCapabilities(network);
        if (null == capabilities) {
            return false;
        }
        return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
                && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
    }


    /**
     * >= Android 10(Q版本)推荐
     *
     * 当前使用WIFI上网
     */

    public static boolean isWifiNetwork(Context context) {
        ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
        Network network = cm.getActiveNetwork();
        if (null == network) {
            return false;
        }
        NetworkCapabilities capabilities = cm.getNetworkCapabilities(network);
        if (null == capabilities) {
            return false;
        }
        return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
                && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
    }


    /**
     *  >= Android 10(Q版本)推荐
     *
     * 当前使用以太网上网
     */
    public static boolean isEthernetNetwork(Context context) {
        ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
        Network network = cm.getActiveNetwork();
        if (null == network) {
            return false;
        }
        NetworkCapabilities capabilities = cm.getNetworkCapabilities(network);
        if (null == capabilities) {
            return false;
        }
        return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
                && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
    }



    /**
     * >= Android 10(Q版本)推荐
     *
     * NetworkCapabilities.NET_CAPABILITY_INTERNET,表示此网络应该(maybe)能够访问internet
     *
     *  判断当前网络可以正常上网
     *  表示此连接此网络并且能成功上网。  例如,对于具有NET_CAPABILITY_INTERNET的网络,这意味着已成功检测到INTERNET连接。
     */
    public static boolean isConnectedAvailableNetwork(Context context) {
        ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
        Network network = cm.getActiveNetwork();
        if (null == network) {
            return false;
        }
        NetworkCapabilities capabilities = cm.getNetworkCapabilities(network);
        if (null == capabilities) {
            return false;
        }
        return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
    }


    /**
     * >= Android 10(Q版本)推荐
     *
     * 获取成功上网的网络类型
     * value = {
     *    TRANSPORT_CELLULAR,   0 表示此网络使用蜂窝传输。
     *    TRANSPORT_WIFI,       1 表示此网络使用Wi-Fi传输。
     *    TRANSPORT_BLUETOOTH,  2 表示此网络使用蓝牙传输。
     *    TRANSPORT_ETHERNET,   3 表示此网络使用以太网传输。
     *    TRANSPORT_VPN,        4 表示此网络使用VPN传输。
     *    TRANSPORT_WIFI_AWARE, 5 表示此网络使用Wi-Fi感知传输。
     *    TRANSPORT_LOWPAN,     6 表示此网络使用LoWPAN传输。
     *    TRANSPORT_TEST,       7 指示此网络使用仅限测试的虚拟接口作为传输。
     *    TRANSPORT_USB,        8 表示此网络使用USB传输
     * }
     */
    public static int getConnectedNetworkType(Context context) {
        ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
        Network network = cm.getActiveNetwork();
        if (null == network) {
            return -1;
        }
        NetworkCapabilities capabilities = cm.getNetworkCapabilities(network);
        if (null == capabilities) {
            return -1;
        }
        if (capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
            if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
                return NetworkCapabilities.TRANSPORT_CELLULAR;
            } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
                return NetworkCapabilities.TRANSPORT_WIFI;
            } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH)) {
                return NetworkCapabilities.TRANSPORT_BLUETOOTH;
            } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
                return NetworkCapabilities.TRANSPORT_ETHERNET;
            } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
                return NetworkCapabilities.TRANSPORT_VPN;
            } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI_AWARE)) {
                return NetworkCapabilities.TRANSPORT_WIFI_AWARE;
            } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_LOWPAN)) {
                return NetworkCapabilities.TRANSPORT_LOWPAN;
            } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_USB)) {
                return NetworkCapabilities.TRANSPORT_USB;
            }
        }
        return -1;
    }
}

Android10之后,请使用新的API方法, 工具类可以根据业务需求去扩展, 供参考。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android 获取网络连接状态新方法 的相关文章

  • Flutter开发之数据存储-2-文件存储(33)

    数据存储部分在移动开发中是非常重要的部分 无论是一些轻量级的数据 如用户信息 APP配置信息等 还是把需要长期存储的数据写入本地文件或者Sqlite3 都离不开数据存储 上一篇SharedPreferences的使用 今天就练习一下文件存储
  • python求平均数、方差、中位数

    CalStatistics py def getNum 获取用户不定长度的输入 nums iNumStr input 请输入数字 回车退出 while iNumStr nums append eval iNumStr iNumStr inp
  • java mysql差异导出_java 如何从零实现一个数据库差异对比工具?

    对比数据的痛苦 不知道你是否也像我一样 在快乐编写代码的时候 必须进行一些数据库的数据对比工作 诚然 一般的数据差异 比如是每一行的内容不同 市场上有比较成熟的 compare2 等对比工具 但是如果是对比数据的每一列是否相同 这个就会变得

随机推荐

  • 机器人教育和编程教育,家长纠结发问:该选哪一个?

    机器人教育和编程教育 家长纠结发问 该选哪一个 很多家长对于机器人教育和编程教育二者之间的关系都不太懂 究竟二者有何不同 学机器人和学编程有冲突吗 孩子要如何选择呢 我们来一一剖析 1机器人教育与编程教育的区别 涵盖范围不一 机器人教育 机
  • eclipse创建webapp 类型的maven项目

    Eclipse配置maven 配置maven的安装目录 打开Eclipse属性设置面板 Window gt Preferences gt Maven 展开Maven配置界面 选择Installations 如下图 add已经下载好的mave
  • 虚拟机配置之系统网络及防火墙配置

    1 查看网络IP和网关 一般不用修改 在此不作说明 2 配置网络IP地址 1 修改IP地址 root hadoop102 vim etc sysconfig network scripts ifcfg eth0 修改并添加为 3 配置主机名
  • C#中的数据库配置

    初用C 做项目的时候将数据库连接字符串放在注册表中 并且专门写一个窗体让用户能够修改 因为用户不可能自己到注册表中去设置 现在想来 其实没必要 在工程中添加新项 选择 应用程序配置文件 默认名是App config 里面的代码如下
  • PAT-1059 C语言竞赛

    1059 C语言竞赛 20 分 C 语言竞赛是浙江大学计算机学院主持的一个欢乐的竞赛 既然竞赛主旨是为了好玩 颁奖规则也就制定得很滑稽 0 冠军将赢得一份 神秘大奖 比如很巨大的一本学生研究论文集 1 排名为素数的学生将赢得最好的奖品 小黄
  • ECCV22 最新论文汇总(目标检测、图像分割、监督学习、GAN等)

    强烈感谢极市平台提供的论文资源 ECCV 2022 已经放榜 共有1629篇论文中选 录用率还不到20 为了让大家更快地获取和学习到计算机视觉前沿技术 作者对ECCV2022最新论文进行追踪 包括分研究方向的论文及代码汇总 本次更新的 EC
  • springboot在集成多数据源+mybatis-plus无法进行分页的BUG

    springboot在集成多数据源 mysql psql 解决多数据源mybatis plus无法进行分页的BUG 1 springboot在集成多数据源 1 1引入依赖 1 2配置yml文件 1 3创建config包 这个只要让Sprin
  • py 语法操作小计

    list只能加 a b set 只能减 a b parser 传参数 test py import argparse parser argparse ArgumentParser description Training GNN on Pa
  • Linux系统编程-终端、进程组、会话

    一 终端的概念 在UNIX系统中 用户通过终端登录系统后得到一个Shell进程 这个终端成为Shell进程的控制终端 Controlling Terminal 进程中 控制终端是保存在PCB中的信息 而fork会复制PCB中的信息 因此由S
  • 百度地图根据经纬度获取实际地理位置Api接口

    1 接口URL http api map baidu com reverse geocoding v3 ak 密钥 output json coordtype bd09ll location 33 35194364323275 117 39
  • 【附源码】单点登录的两种实现方式

    概念 单点登录 Single Sign On SSO 是一种身份验证服务 允许用户使用单个标识来登录多个应用程序或系统 如下图所示 用户只需要用户名 密码登陆一次就可以访问系统A 系统B和系统C 在传统的登录方式中 用户必须为每个应用程序或
  • 目录扫描,请求重发,漏洞扫描等工具的使用

    本专栏是笔者的网络安全学习笔记 一面分享 同时作为笔记 工欲善其事必先利其器 本篇讲解一些常用工具的使用 前文链接 WAMP DVWA sqli labs 搭建 burpsuite工具抓包及Intruder暴力破解的使用 用到的工具 bur
  • 7天学完Spring:AOP实战,SpringMVC统一处理

    目录 前言 一丶用户登录权限效验 lt 1 gt 最初用户登录验证 lt 2 gt Spring AOP 用户统一登录验证的问题 lt 3 gt 拦截器 拦截功能演示 lt 4 gt 拦截器原理 lt 5 gt 统一访问前缀添加 二丶统一异
  • 操作系统期末习题考试习题解答题目三

    操作系统期末习题考试习题解答题目三 目录 操作系统期末习题考试习题解答题目三 第八章 第九章 第八章 1 什么是文件 文件系统 文件系统有哪些功能 P198 答 在计算机系统中 文件被解释为一组赋名的相关字符流的集合 或者是相关纪录的集合
  • 理解git存储原理

    git是一个文件寻址系统 什么是文件寻址 其实我也不是很理解 哈哈哈 Git 的底层存储从本质上讲是基于本地文件系统实现的 Key Value 数据库 这里的 Value 是 git 里的三种不同的对象的内容 而 Key 则是对象内容的 h
  • VML Mathematical Functions

    http www physics ntua gr konstant HetCluster intel12 1 mkl mkl manual GUID 7B3B6537 71E2 4BF5 A041 0365E72B211B htm TBL9
  • opencv c++ 贴图补齐实战

    目录 创建黑图 int8类型贴图补齐 测试时间 fx缩放 贴图 float32类型贴图
  • ChatGPT作者John Shulman:我们成功的秘密武器

    推荐 深度学习与NLP 来源 转载自OneFlow 杨婷 徐佳渝翻译 除了OpenAI 外界可能很少有人知道ChatGPT模型成功的真正原因 实际上 OpenAI也会对ChatGPT拥有的巨大影响力感到不可思议 这种困惑和惊喜就像工程师们解
  • CV-第三方库:OpenMMLab---->MMClassification

    MMClassification 是一款基于 PyTorch 的开源图像分类工具箱 是 OpenMMLab 项目的成员之一 主分支代码目前支持 PyTorch 1 5 以上的版本 主要特性 支持多样的主干网络与预训练模型 支持配置多种训练技
  • Android 获取网络连接状态新方法

    一 问题背景 Android12上 有的app模块判断当前网络的类型和连接状态时 还是使用的旧的API 导致返回的结果不准确 影响代码逻辑判断 本篇文章就这一问题 整理一下判断网络类型和连接状态的新方法 二 原因分析 在Android 10