如何使用 ConnectivityManager.NetworkCallback 监听 WiFi 和移动网络状态?

3
前提条件是同时使用wifi和移动网络。在我关闭wifi后,ConnectivityManager.NetworkCallback的onLost函数突然被调用。这就是为什么ConnectivityManager中的NetworkInfo为空的问题所在。
但是如果我使用Thread.sleep()等待3秒钟,它就能正常工作。
我想知道使用ConnectivityManager.NetworkCallback来检查网络状态的正确方法是什么。
new ConnectivityManager.NetworkCallback() {
    @Override
    public void onAvailable(Network network) {
        Log.d(TAG, "ConnectivityManager.NetworkCallback:onAvailable");
        context.sendBroadcast(getNetworkStateIntent(isAvailable(context)));
    }

    @Override
    public void onLosing(Network network, int maxMsToLive) {
        Log.d(TAG, "ConnectivityManager.NetworkCallback:onLosing");
    }

    @Override
    public void onLost(Network network) {
        Log.d(TAG, "ConnectivityManager.NetworkCallback:onLost");
        context.sendBroadcast(getNetworkStateIntent(isAvailable(context)));
    }

    @Override
    public void onUnavailable() {
        Log.d(TAG, "ConnectivityManager.NetworkCallback:onUnavailable");
        context.sendBroadcast(getNetworkStateIntent(isAvailable(context)));
    }
};

private boolean isAvailable(Context context) {
    Log.d(TAG, "isAvailable");
    ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetworkInfo = cm.getActiveNetworkInfo();
    Log.d(TAG, "activeNetworkInfo:" + activeNetworkInfo);
    NetworkInfo mWifi = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
    Log.d(TAG, "wifi:" + mWifi);
    NetworkInfo mMobile = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
    Log.d(TAG, "mobile:" + mMobile);

    if(activeNetworkInfo == null) {
        Log.d(TAG, "false 'cause activeNetworkInfo is null");
        return false;
    }

    int type = activeNetworkInfo.getType();
    switch(type) {
        case ConnectivityManager.TYPE_WIFI:
        case ConnectivityManager.TYPE_MOBILE:
        case ConnectivityManager.TYPE_ETHERNET:
            Log.d(TAG, "true");
            return true;
        default:
            Log.d(TAG, "false 'cause of type");
            return false;
    }
}

你找到解决方案了吗? - Ahmed Mahmoud
你的NetworkRequest的代码在回答问题时会很有用。 - Always Learning
1个回答

2
基于你不断监听设备是否联网的假设,我已经完成了以下操作:
  1. 将网络列表存储在LiveData类中,并在新的onAvailable回调中添加网络,以便我们将所有剩余的活动网络存储在某个地方。(虽然可以通过ConnectivityManager获取它们,但我更喜欢这种方式)
  2. 当用户或系统禁用网络时,我们会从网络ArrayList中删除该网络。
  3. 每次我们失去网络时,我们会从列表中删除它,并检查列表中所有剩余的网络是否能够在root-servers.net服务器上执行查询,以确定我们是否有互联网访问权限。
下面是LiveData类的代码:
class LiveDataNetworkStatus(context: Context) : LiveData<Boolean>() {

    companion object {
        const val ROOT_SERVER_CHECK_URL = "a.root-servers.net"
    }

    private val connectivityManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
    private val networks: ArrayList<Network> = ArrayList()

    private val networkStateObject = object : ConnectivityManager.NetworkCallback() {
        override fun onLost(network: Network) {
            super.onLost(network)
            networks.remove(network)
            postValue(!networks.all { !checkInternetConnectivity(it) })
        }

        override fun onAvailable(network: Network) {
            super.onAvailable(network)
            networks.add(network)
            postValue(checkInternetConnectivity(network))
        }

        fun checkInternetConnectivity(network: Network): Boolean {
            return try {
                network.getByName(ROOT_SERVER_CHECK_URL) != null
            } catch (e: UnknownHostException) {
                false
            }
        }
    }

    override fun onActive() {
        super.onActive()
        connectivityManager.registerNetworkCallback(networkRequestBuilder(), networkStateObject)
        postValue(false) // Consider all networks "unavailable" on start
    }

    override fun onInactive() {
        super.onInactive()
        connectivityManager.unregisterNetworkCallback(networkStateObject)
    }

    private fun networkRequestBuilder(): NetworkRequest {
        return NetworkRequest.Builder()
            .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
            .build()
    }
}

由于系统从Wi-Fi切换到蜂窝网络导致的“断开连接”状态将通过此LiveData类传输,我们对此无能为力。但是一旦蜂窝网络激活,当前的LiveData类将返回新的网络可用性状态(true)。
如果您有问题或意见,请不要犹豫。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接