兼容Android29的网络连接及网络状态工具。

最近项目升级到Android29版本发现网络连接及网络类型的好多方法都被弃用了。比如以往获取网络状态我们会使用NetworkInfo来获取但是现在这个类已经完全被抛弃了。而Google官网推荐我们使用ConnectivityManager#NetworkCallback回调的这种方式,也可以使用ConnectivityManager#getNetworkCapabilities或者ConnectivityManager#getLinkProperties的方式直接获取网络类型等信息。官网地址:https://developer.android.google.cn/reference/android/net/NetworkInfo

那如何通过Android29提供的新API后去网络连接及状态。

通过上图大家可以大概了解到获取网络连接及状态的几个类。其中NetworkManager是一个单例用来管理和分发网络连接及状态。NetworkCallbackImpl是ConnectivityManager#NetworkCallback的实现类用来获取网络变化是的连接状态和网络类型。Network中包含的是一些回调的抽象类、枚举、公共的一些方法等。最下面的NetworkReceiver和NetworkService是为了兼容Android21版本以下的终端获取网络连接和状态使用的类。

首先我们先从NetworkCallbackImpl类说起,这个类继承了ConnectivityManager#NetworkCallback并实现了其中的三个方法。请看如下代码:

@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
class NetworkCallbackImpl(val isConnection: (isconn: Boolean) -> Unit, val getNetType: (type: NetType) -> Unit) : ConnectivityManager.NetworkCallback() {
    /**
     * 网络连接方法
     * @param network
     */
    override fun onAvailable(network: Network) {
        super.onAvailable(network)
        isConnection(true)
    }

    /**
     * 网络断开方法
     * @param network
     */
    override fun onLost(network: Network) {
        super.onLost(network)
        isConnection(false)
    }

    /**
     * 检测网络类型
     * @param network
     * @param networkCapabilities
     */
    override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
        super.onCapabilitiesChanged(network, networkCapabilities)
        if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
            getNetType(getNetType21(networkCapabilities))
        }
    }
}

其中onAvailable方法在通过ConnectivityManager中注册的时候会调用一次,而后当网络断开后再次连接会被再次调用。onLost也是如此。但是在这里需要强调一点onCapabilitiesChanged方法在注册的时候不会回调只能等到网络重新连接该方法才会回调。这样就会导致我们打开程序的时候获取不到网络类型。不过没有关系因为ConnectivityManager类给我们提供了getNetworkCapabilities方法,可以手动获取当先网络类型(这个少狗再说)。该类中我还传递了两个方法isConnection和getNetType用来通知Manager当前网络的相关信息。

需要注意的是在onCapabilitiesChanged中用到了getNetType21方法可以通过反馈的NetworkCapabilities获取到网络类型。该类型如下几种

private static final String[] TRANSPORT_NAMES = {
        "CELLULAR",
        "WIFI",
        "BLUETOOTH",
        "ETHERNET",
        "VPN",
        "WIFI_AWARE",
        "LOWPAN",
        "TEST"
    };

这七种类型所对应的常亮标记为:

 /**
     * 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;

接下来看一下NetworkManager管理器。管理器主要的作用就是初始化ConnectivityManager对象,注册我们继承的NetworkCallBack对象及注册回调等功能,想必这个一看代码就能够理解很简单无难度。

/**
     * 初始化方法
     */
    @SuppressLint("MissingPermission")
    fun init(context: Context) {
        mContext = context
        if (isHigherThenLollipop()) {
            networkCallbackImpl = NetworkCallbackImpl(::observerIsConnection, ::observerNetWorkType)
            val request = NetworkRequest.Builder().build()
            val manager = INSTANCE.mContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            manager.registerNetworkCallback(request, networkCallbackImpl)
            netType = if (isHigherThenM()) {
                try {
                    val capabilities = manager.getNetworkCapabilities(manager.activeNetwork)
                    getNetType21(capabilities)
                }catch (e : Exception){
                    e.printStackTrace()
                    NetType.NONE
                }
            } else {
                getNetType(manager)
            }
        } else {
            if (!EventBus.getDefault().isRegistered(INSTANCE))
                EventBus.getDefault().register(INSTANCE)
            //开启服务
            mContext.startService(Intent(mContext, NetworkService::class.java))
        }
    }

初始化方法用于注册NetworkCallback子类对象到ConnectivityManager中。后面判断版本是否高于M(isHigherThenM)是为了解决注册时候的时候不能回调onCapabilitiesChanged方法而无法获取网络类型问题。其中getNetType21是Android21版本以上的获取方法,21版本一下获取方式使用的是getNetType方法获取。具体代码可以下载文末的Demo。位置在Network.kt文件中。

状态的分发本来想使用Java反射的方式进行事件的分发,但是有一个问题就是如果使用反射就涉及到代码混淆的问题。为了避免这个问题选择了回调。感兴趣的朋友也可以使用EventBus或者其他方式。如果有更好的方法希望在评论区转告我谢谢。

演示代码地址:https://github.com/liming870906/NetworkTools/tree/master

猜你喜欢

转载自blog.csdn.net/laowu119119/article/details/106260059