Android ConnectivityManager的onAvailable有时未返回

8
我们使用Android的ConnectivityManager在应用程序内监听互联网连接的更改,如下所示。
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        ConnectionStateMonitor().enable(this)
    }

    class ConnectionStateMonitor : NetworkCallback() {
        private val networkRequest: NetworkRequest = NetworkRequest.Builder()
            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
            .addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build()

        fun enable(context: Context) {
            val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            connectivityManager.registerNetworkCallback(networkRequest, this)
        }

        override fun onAvailable(network: Network) {
            Log.i(TAG, "onAvailable ")
        }

        override fun onLost(network: Network?) {
            super.onLost(network)
            Log.i(TAG, "onLost ")
        }
    }
}

这个实现很好用,除了两个问题:

  1. 如果我们同时使用Wi-Fi和蜂窝数据连接到互联网,并关闭Wi-Fi,有时会依次触发onLost()回调和onAvailable()回调,正如预期。但在其他情况下,只有onLost()回调被触发,这是不正确的。

  2. 如果我们没有互联网连接并打开应用,则onLost()不会被触发,然而如果我们有互联网连接并打开应用,则onAvailable()会被触发。

非常感谢任何对可靠检测网络连接变化的帮助、建议、解决方法或其他方法。

在Xioami A2(Android 9)和OnePlus(Android 9)上测试通过。

演示项目
https://github.com/PhanVanLinh/AndroidNetworkChangeReceiver


你找到解决你的第二个问题的方法了吗? - nAkhmedov
不,我找不到答案,所以我从我的应用程序中删除了这个功能。我仍在寻找解决方案。 - Linh
4个回答

3

我使用了你的项目,并添加了一个方法:onCapabilitiesChanged。我先启用了飞行模式然后再关闭,然后重新打开。这是日志:

onAvailable 632

onCapabilitiesChanged 632 [传输:蜂窝数据 ...]

onAvailable 632

onCapabilitiesChanged 632 [传输:蜂窝数据 ...]

onAvailable 632

onCapabilitiesChanged 632 [传输:蜂窝数据 ...]

onCapabilitiesChanged 632 [传输:蜂窝数据 ...]

onCapabilitiesChanged 632 [传输:蜂窝数据 ...]

onAvailable 633

onCapabilitiesChanged 633 [传输:Wi-Fi ...] onAvailable 633   onCapabilitiesChanged 633 [传输:Wi-Fi ...]

onAvailable 633

onCapabilitiesChanged 633 [传输:Wi-Fi ...]

onCapabilitiesChanged 633 [传输:Wi-Fi ...]

onCapabilitiesChanged 633 [传输:Wi-Fi ...]

onCapabilitiesChanged 633 [传输:Wi-Fi ...]

onCapabilitiesChanged 633 [传输:Wi-Fi ...]

onCapabilitiesChanged 633 [传输:Wi-Fi ...]

onLost 632

onLost 632

onLost 632

onLost 633

onLost 633

onLost 633

onAvailable 634

onCapabilitiesChanged 634 [传输:蜂窝数据 ...]

onAvailable 634

onCapabilitiesChanged 634 [传输:蜂窝数据 ...]

onAvailable 634

onCapabilitiesChanged 634 [传输:蜂窝数据 ...]

onCapabilitiesChanged 634 [传输:蜂窝数据 ...]

onCapabilitiesChanged 634 [传输:蜂窝数据 ...]

onCapabilitiesChanged 634 [传输:蜂窝数据 ...]

onAvailable 635

onCapabilitiesChanged 635 [传输:Wi-Fi ...]

onAvailable 635

onCapabilitiesChanged 635 [传输:Wi-Fi ...]

onAvailable 635

onCapabilitiesChanged 635 [传输:Wi-Fi ...]

onCapabilitiesChanged 635 [传输:Wi-Fi ...]

onCapabilitiesChanged 635 [传输:Wi-Fi ...]

onCapabilitiesChanged 635 [传输:Wi-Fi ...]

onLost 634

onLost 634

onLost 634

onCapabilitiesChanged 635 [传输:Wi-Fi ...]

onCapabilitiesChanged 635 [传输:Wi-Fi ...]

如您所见,LOST 是指移动网络传输,而 AVAILABLE 是指 WiFi
根据您的使用情况(启用 WiFi、启用移动数据、禁用 WiFi 数据、启用 WiFi、禁用 WiFi),我得到了以下结果。

onAvailable 640

onCapabilitiesChanged 640 [ Transports: WIFI ... ]

onAvailable 640

onCapabilitiesChanged 640 [ Transports: WIFI ... ]

onCapabilitiesChanged 640 [ Transports: WIFI ... ]

onCapabilitiesChanged 640 [ Transports: WIFI ... ]

onCapabilitiesChanged 640 [ Transports: WIFI ... ]

onCapabilitiesChanged 640 [ Transports: WIFI ... ]

onLost 640

onLost 640

onAvailable 641

onCapabilitiesChanged 641 [ Transports: CELLULAR ... ]

onAvailable 641

onCapabilitiesChanged 641 [ Transports: CELLULAR ... ]

onCapabilitiesChanged 641 [ Transports: CELLULAR ... ]

onCapabilitiesChanged 641 [ Transports: CELLULAR ... ]

onAvailable 642

onCapabilitiesChanged 642 [ Transports: WIFI ... ]

onAvailable 642

onCapabilitiesChanged 642 [ Transports: WIFI ... ]

onCapabilitiesChanged 642 [ Transports: WIFI ... ]

onCapabilitiesChanged 642 [ Transports: WIFI ... ]

onCapabilitiesChanged 642 [ Transports: WIFI ... ]

onCapabilitiesChanged 642 [ Transports: WIFI ... ]

onLost 641

onLost 641

onLost 642

onLost 642

onAvailable 643

onCapabilitiesChanged 643 [ Transports: CELLULAR ... ]

onAvailable 643

onCapabilitiesChanged 643 [ Transports: CELLULAR ... ]

onCapabilitiesChanged 643 [ Transports: CELLULAR ... ]

onCapabilitiesChanged 643 [ Transports: CELLULAR ... ]


感谢您的测试。我已经阅读了您的日志三次,但仍然无法理解。目前,如果您有安卓9设备,您可以再次进行几次测试,例如:`启用WiFi,启用移动数据,禁用WiFi数据,启用WiFi,禁用WiFi(通常不会调用onAvailable)。您可以尝试几次,就会发现问题所在。在我的安卓8设备上,一切都运行良好,但我不确定所有安卓8设备是否都能正常工作。 - Linh
每次我关闭Wifi(即使是最后一次),它都会为我调用可用的蜂窝网络。我正在使用安卓9的三星Note 8。 - kingston
再试一次,当我打开Wifi时,我没有收到移动网络的onLost信号,然后当我关闭Wifi时,我也没有收到onAvailable信号。 - kingston
onCapabilitiesChanged 应该可以解决问题。我之前也遇到了类似的问题,通过添加检查有效互联网的条件 networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) 帮助了我。 - Rafael

2
回调函数应该长这样:
val callback = object : ConnectivityManager.NetworkCallback() {

    private val availableNetworks: MutableSet<Network> = HashSet()

    override fun onAvailable(network: Network) {
        val networkCapabilities = connectivityManager.getNetworkCapabilities(network)
        val hasInternetCapability =
            networkCapabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)

        if (hasInternetCapability == true) {
            availableNetworks.add(network)
            sendNetworkState()
        }
    }

    override fun onLost(network: Network) {
        availableNetworks.remove(network)
        sendNetworkState()
    }

    private fun sendNetworkState() {
        if (availableNetworks.isNotEmpty()) {
            // TODO: Notify the Internet connection is available
        } else {
            // TODO: Notify the Internet connection is unavailable
        }
    }
}

注册回调函数:

val request = NetworkRequest.Builder()
    .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
    .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
    .build()

connectivityManager.registerNetworkCallback(networkRequest, callback)

解释

onLost会针对之前传递给onAvailable的每个网络进行调用,根据文档:

如果使用registerNetworkCallback()注册回调,则它将对不再满足回调条件的每个网络进行调用。

这也可能导致在onLost之前onAvailable被调用两次。

代码最初来源于此处:https://www.youtube.com/watch?v=To9aHYD5OVk


1
AndroidManifest中广播接收器的定义已经有所改变。您可以在这里找到相应的描述。
您已经按照这种方式实现了,但是无论如何,我想添加网络回调类引用作为参考点。

1
我阅读了你在Github上的源代码,发现你的主要想法是每5秒检查一次互联网状态。如果这是正确的,我觉得它对性能来说不是很好。有没有什么优化的方法?如果我错了,请纠正我。 - Linh
嗨,Linh,我能理解你的担忧,好的,那么我会更新答案的上下文,也许你可以在developer.android.com上找到另一个解决方案。 - nurisezgin
是的,实际上监听互联网连接变化只是对我的应用程序进行了一点改进。如果它消耗太多电池,我认为我不需要把它放在里面,因为它没有太多的好处。现在我已经从我的应用程序中删除了这个功能:D,只有当调用API时没有互联网连接时,我会显示错误:v - Linh

1
也许您可以尝试使用requestNetwork而不是registerNetworkCallback

这不会改变任何与onAvailable相关的内容。两者之间唯一的行为差异在于,requestNetwork将为您的应用程序保持网络连接,而registerNetworkCallback则不会。也就是说,如果没有应用程序打开特定网络的requestNetwork请求,则ConnectivityService将关闭它。但是,对于此类registerNetworkCallback类型的请求,它并不关心。 - Always Learning

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