监听网络变化--含7.0以上适配_android.net.conn.connectivity_change-程序员宅基地

技术标签: android  

我们知道最早监听网络变化,是通过广播,静态或动态注册广播,处理"android.net.conn.CONNECTIVITY_CHANGE"这个action就可以了intent就可以了。

我们发现"android.net.conn.CONNECTIVITY_CHANGE"这个action已经加了注解@Deprecated,不推荐使用了。根据注释说明,7.0及以上静态注册广播(manifest中)不能收到这个广播了,但是动态注册的广播还可以收到。 所以一般思路就是 判断一下,7.0及以后 增加动态注册就可以了。

同时还有一段说明,说应该使用 更牛逼、 更多功能、更多细节的 {@link #requestNetwork},
{@link #registerNetworkCallback} or {@link #registerDefaultNetworkCallback}。

注意到这些方式是回调的方式,也必须APP运行才可以了。我们知道 静态注册广播接收器不需要App运行也能收到, 也就是说随着系统的更迭,网络变化的获取只能在App运行期间了。这是Android系统对权限的限制。
在这里插入图片描述同时注意到,推荐使用的方法要求是 在5.0及以上的。
在这里插入图片描述
所以总结一下就是两个方式处理网络变化监听的适配了:
1、使用广播,7.0及7.0以前使用静态注册,以后使用动态注册。(或者直接 全版本使用动态注册)
2、7.0以前使用静态广播,7.0及以后使用回调方式registerNetworkCallback等。
(或者5.0以前使用广播(动态或静态),5.0及一会使用回调方式)

因为新的回调方式,可以提供更细节更牛逼的功能,且是官方推荐的,那就采用第2个方法。

关于registerNetworkCallback(NetworkRequest request, NetworkCallback networkCallback)参数NetworkCallback 回调方法的说明,建议查看官方文档,这里简单说明:

public static class NetworkCallback {
    
        /**
         *连接网络了,开计算是否满足要求
         */
        public void onPreCheck(Network network) {
    }

        /**
         * 网络准备可用了
         */
        public void onAvailable(Network network, NetworkCapabilities networkCapabilities,
                LinkProperties linkProperties) {
    
                
            onAvailable(network);
            if (!networkCapabilities.hasCapability(
                    NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)) {
    
                onNetworkSuspended(network);
            }
            onCapabilitiesChanged(network, networkCapabilities);
            onLinkPropertiesChanged(network, linkProperties);
        }

        /**
         * 网络准备可用了
         */
        public void onAvailable(Network network) {
    }

        /**
         * 网络将要断开
         */
        public void onLosing(Network network, int maxMsToLive) {
    }

        /**
         * 网络断开
         */
        public void onLost(Network network) {
    }

        /**
         * 网络不可用
         */
        public void onUnavailable() {
    }

        /**
         * 网络能力变化,还是可用状态,可能多次调用
         */
        public void onCapabilitiesChanged(Network network,
                NetworkCapabilities networkCapabilities) {
    }

        /**
         * 链接属性改变
         */
        public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {
    }

        /**
         * 网络暂停
         */
        public void onNetworkSuspended(Network network) {
    }

        /**
         * 网络恢复
         */
        public void onNetworkResumed(Network network) {
    }

        private NetworkRequest networkRequest;
    }

回调方法很多,网络变化的各种状态,广播是没有这个功能的。这些方法的回调时机可以自行测试,或者看这篇android 5.0 以上监听网络变化

下面就给出我的实现方式

/**
 * 网络连接变化 监听帮助类
 *
 * 说明:
 * 1、静态注册广播监听网络变化 的方式,{@link ConnectivityManager#CONNECTIVITY_ACTION}已有说明,
 *      7.0及以后 静态注册的接收器不会收到 CONNECTIVITY_ACTION,只能用动态注册。(这是官方对广播权限的限制)
 * 2、5.0后有新的api{@link ConnectivityManager.NetworkCallback} ,但是只能在app 存活时监听到。和动态注册效果类似,但有更多细节的回调。
 *
 * 综合这两点,本类实现方案:7.0及以后使用新api,只能在app存活时接收到回调;7.0以前使用静态注册广播。
 */
public class NetworkChangeListenHelper {
    

    /**
     * 网络不可用
     */
    private static final int NETWORK_STATE_UNAVAILABLE = -1;
    
    /**
     * 网络可用
     */
    private static final int NETWORK_STATE_AVAILABLE = 0;

//    /**
//     * 网络可用,且是移动数据
//     */
//    private static final int NETWORK_STATE_AVAILABLE_MOBILE = 1;
//
//    /**
//     * 网络可用,且是wifi
//     */
//    private static final int NETWORK_STATE_AVAILABLE_WIFI = 2;

    private static NetworkChangeListener mNetworkChangeListener;

    public boolean hasRegistNetworkCallback(){
    
        return mNetworkChangeListener != null;
    }

    public void registerNetworkCallback(NetworkChangeListener networkChangeListener) {
    
        if (hasRegistNetworkCallback()) {
    
            XLogUtil.d("hasRegistNetworkCallback");
            return;
        }

        mNetworkChangeListener = networkChangeListener;

        //7.0及以后 使用这个新的api(7.0以前还是用静态注册广播)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    
            ConnectivityManager connectivityManager = (ConnectivityManager) MyApplication.getInstance().getSystemService(Context.CONNECTIVITY_SERVICE);
            // 请注意这里会有一个版本适配bug,所以请在这里添加非空判断
            if (connectivityManager != null) {
    
                NetworkRequest request = new NetworkRequest.Builder().build();
                connectivityManager.registerNetworkCallback(request, new AkuNetworkCallback());
            }

        }
    }

    private void handleOnNetworkChange(int networkState) {
    
        if (mNetworkChangeListener == null) {
    
            return;
        }
        switch (networkState){
    
            case NETWORK_STATE_UNAVAILABLE:
                mNetworkChangeListener.onNetworkChange(false);
                break;
            case NETWORK_STATE_AVAILABLE:
                mNetworkChangeListener.onNetworkChange(true);
                break;
//            case NETWORK_STATE_AVAILABLE_WIFI:
//                mNetworkChangeListener.onNetworkChange(true);
//                break;
            default:
                break;
        }

    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public class AkuNetworkCallback extends ConnectivityManager.NetworkCallback{
    

        @Override
        public void onAvailable(Network network) {
    
            super.onAvailable(network);
            XLogUtil.d("网络连接了");
            handleOnNetworkChange(NETWORK_STATE_AVAILABLE);
        }

        @Override
        public void onLost(Network network) {
    
            super.onLost(network);
            XLogUtil.d("网络断开了");
            handleOnNetworkChange(NETWORK_STATE_UNAVAILABLE);
        }

        @Override
        public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
    
            super.onCapabilitiesChanged(network, networkCapabilities);
            //网络变化时,这个方法会回调多次
            if(networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)){
    
                if(networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)){
    
                    XLogUtil.d("wifi网络已连接");
//                    handleOnNetworkChange(NETWORK_STATE_AVAILABLE_WIFI);

                }else {
    
                    XLogUtil.d("移动网络已连接");
//                    handleOnNetworkChange(NETWORK_STATE_AVAILABLE_MOBILE);
                }
            }
        }

    }

    public static class NetworkChangeBroadcastReceiver extends BroadcastReceiver{
    

        @Override
        public void onReceive(Context context, Intent intent) {
    
            //7.0以下用静态广播
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
    
                return;
            }
            if (intent == null) {
    
                return;
            }

            if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
    
                return;
            }

            if (mNetworkChangeListener == null) {
    
                return;
            }

            boolean noConnectivity = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);

            mNetworkChangeListener.onNetworkChange(!noConnectivity);
        }
    }

    /**
     * NetworkChangeListener
     */
    public interface NetworkChangeListener {
    
        void onNetworkChange(boolean isNetworkAvailable);
    }
}

使用方式,很简单

	/**
     * 监听网络变化
     */
    private static void registerNetworkListener() {
    
        if (mNetworkChangeListenHelper != null && mNetworkChangeListenHelper.hasRegistNetworkCallback()) {
    
            return;
        }

        mNetworkChangeListenHelper = new NetworkChangeListenHelper();
        mNetworkChangeListenHelper.registerNetworkCallback(new NetworkChangeListenHelper.NetworkChangeListener() {
    
            @Override
            public void onNetworkChange(boolean isNetworkAvailable) {
    
                if (!isNetworkAvailable) {
    
                	//没网啦,do something
                    return;
                }
                
                //有网啦,do something
                
            }
        });
    }

别忘了,在manifest中注册:

<receiver
android:name=".NetworkChangeListenHelper$NetworkChangeBroadcastReceiver"
            android:exported="true">
            <intent-filter >
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
                <action android:name="android.Net.wifi.WIFI_STATE_CHANGED" />
                <action android:name="android.net.wifi.STATE_CHANGE" />
            </intent-filter>
 </receiver>

好了,讲完啦~

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/hfy8971613/article/details/103336951

智能推荐

前端开发之vue-grid-layout的使用和实例-程序员宅基地

文章浏览阅读1.1w次,点赞7次,收藏34次。vue-grid-layout的使用、实例、遇到的问题和解决方案_vue-grid-layout

Power Apps-上传附件控件_powerapps点击按钮上传附件-程序员宅基地

文章浏览阅读218次。然后连接一个数据源,就会在下面自动产生一个添加附件的组件。把这个控件复制粘贴到页面里,就可以单独使用来上传了。插入一个“编辑”窗体。_powerapps点击按钮上传附件

C++ 面向对象(Object-Oriented)的特征 & 构造函数& 析构函数_"object(cnofd[\"ofdrender\"])十条"-程序员宅基地

文章浏览阅读264次。(1) Abstraction (抽象)(2) Polymorphism (多态)(3) Inheritance (继承)(4) Encapsulation (封装)_"object(cnofd[\"ofdrender\"])十条"

修改node_modules源码,并保存,使用patch-package打补丁,git提交代码后,所有人可以用到修改后的_修改 node_modules-程序员宅基地

文章浏览阅读133次。删除node_modules,重新npm install看是否成功。在 package.json 文件中的 scripts 中加入。修改你的第三方库的bug等。然后目录会多出一个目录文件。_修改 node_modules

【】kali--password:su的 Authentication failure问题,&sudo passwd root输入密码时Sorry, try again._password: su: authentication failure-程序员宅基地

文章浏览阅读883次。【代码】【】kali--password:su的 Authentication failure问题,&sudo passwd root输入密码时Sorry, try again._password: su: authentication failure

整理5个优秀的微信小程序开源项目_微信小程序开源模板-程序员宅基地

文章浏览阅读1w次,点赞13次,收藏97次。整理5个优秀的微信小程序开源项目。收集了微信小程序开发过程中会使用到的资料、问题以及第三方组件库。_微信小程序开源模板

随便推点

Centos7最简搭建NFS服务器_centos7 搭建nfs server-程序员宅基地

文章浏览阅读128次。Centos7最简搭建NFS服务器_centos7 搭建nfs server

Springboot整合Mybatis-Plus使用总结(mybatis 坑补充)_mybaitis-plus ruledataobjectattributemapper' and '-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏3次。前言mybatis在持久层框架中还是比较火的,一般项目都是基于ssm。虽然mybatis可以直接在xml中通过SQL语句操作数据库,很是灵活。但正其操作都要通过SQL语句进行,就必须写大量的xml文件,很是麻烦。mybatis-plus就很好的解决了这个问题。..._mybaitis-plus ruledataobjectattributemapper' and 'com.picc.rule.management.d

EECE 1080C / Programming for ECESummer 2022 Laboratory 4: Global Functions Practice_eece1080c-程序员宅基地

文章浏览阅读325次。EECE 1080C / Programming for ECESummer 2022Laboratory 4: Global Functions PracticePlagiarism will not be tolerated:Topics covered:function creation and call statements (emphasis on global functions)Objective:To practice program development b_eece1080c

洛谷p4777 【模板】扩展中国剩余定理-程序员宅基地

文章浏览阅读53次。被同机房早就1年前就学过的东西我现在才学,wtcl。设要求的数为\(x\)。设当前处理到第\(k\)个同余式,设\(M = LCM ^ {k - 1} _ {i - 1}\) ,前\(k - 1\)个的通解就是\(x + i * M\)。那么其实第\(k\)个来说,其实就是求一个\(y\)使得\(x + y * M ≡ a_k(mod b_k)\)转化一下就是\(y * M ...

android 退出应用没有走ondestory方法,[Android基础论]为何Activity退出之后,系统没有调用onDestroy方法?...-程序员宅基地

文章浏览阅读1.3k次。首先,问题是如何出现的?晚上复查代码,发现一个activity没有调用自己的ondestroy方法我表示非常的费解,于是我检查了下代码。发现再finish代码之后接了如下代码finish();System.exit(0);//这就是罪魁祸首为什么这样写会出现问题System.exit(0);////看一下函数的原型public static void exit (int code)//Added ..._android 手动杀死app,activity不执行ondestroy

SylixOS快问快答_select函数 导致堆栈溢出 sylixos-程序员宅基地

文章浏览阅读894次。Q: SylixOS 版权是什么形式, 是否分为<开发版税>和<运行时版税>.A: SylixOS 是开源并免费的操作系统, 支持 BSD/GPL 协议(GPL 版本暂未确定). 没有任何的运行时版税. 您可以用她来做任何 您喜欢做的项目. 也可以修改 SylixOS 的源代码, 不需要支付任何费用. 当然笔者希望您可以将使用 SylixOS 开发的项目 (不需要开源)或对 SylixOS 源码的修改及时告知笔者.需要指出: SylixOS 本身仅是笔者用来提升自己水平而开发的_select函数 导致堆栈溢出 sylixos

推荐文章

热门文章

相关标签