如何确定在恢复 Android 应用程序时互联网访问不可用

发布于 2025-01-09 09:51:52 字数 3396 浏览 3 评论 0原文

我当前的 Android 应用程序需要在用户会话期间丢失互联网访问时通知用户

我使用以下回调侦听器:-

@OptIn(DelicateCoroutinesApi::class)
class ConnectivityListener @Inject constructor() : CoroutineScope by GlobalScope, ConnectivityManager.NetworkCallback() {

    private var backgroundStateJob: Job? = null
    private val internalSharedWorkState = MutableSharedFlow<BackgroundState>(replay = 1, extraBufferCapacity = 7, onBufferOverflow = BufferOverflow.DROP_OLDEST)
    private val sharedWorkScheduleState: SharedFlow<BackgroundState> = internalSharedWorkState

    override fun onBlockedStatusChanged(network: Network, blocked: Boolean) {
        Timber.e( "onBlockedStatusChanged() called with: network = $network, blocked = $blocked")
    }
    override fun onLosing(network: Network, maxMsToLive: Int) {
        Timber.e( "onLosing() called with: network = $network, maxMsToLive = $maxMsToLive")
    }
    override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
        Timber.e( "onCapabilitiesChanged() called with: network = $network, networkCapabilities = $networkCapabilities")
    }
    override fun onLinkPropertiesChanged(network: Network, linkProperties: LinkProperties) {
        Timber.e( "onLinkPropertiesChanged() called with: network = $network, linkProperties = $linkProperties")
    }
    override fun onUnavailable() {
        Timber.e( "onUnavailable() called")
    }

    override fun onAvailable(network: Network) {
        Timber.e("onAvailable() called with: network = $network")
        backgroundStateJob?.cancel()
        backgroundStateJob = launch(Dispatchers.IO) {
            internalSharedWorkState.emit(BackgroundState.Connected())
        }
    }

    override fun onLost(network: Network) {
        Timber.e("onLost() called with: network = $network")
        backgroundStateJob?.cancel()
        backgroundStateJob = launch(Dispatchers.IO) {
            internalSharedWorkState.emit(BackgroundState.Disconnected())
        }
    }

    fun stateFlow(): SharedFlow<BackgroundState> {
        return sharedWorkScheduleState
    }
}

此侦听器在我的基本活动中使用,如下所示:-

private val networkRequest = NetworkRequest.Builder()
    .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
    .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
    .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
    .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
    .build()

...

 override fun onResume() {
        Timber.e("onResume() called")
        super.onResume()
        val connectivityManager = this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        connectivityManager.registerNetworkCallback(networkRequest, connectivityListener)

    }

    override fun onPause() {
        Timber.e("onPause() called")
        super.onPause()
        val connectivityManager = this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        connectivityManager.unregisterNetworkCallback(connectivityListener)
    }

当应用程序运行时,侦听器按预期工作每当互联网访问丢失时,可靠的信息都会在前台通知用户当前的网络状态。

当我退出应用程序时,侦听器也可以正常工作,它会进入后台并随后恢复。听众成功报告我可以访问互联网。

但是,当我将应用程序置于后台、启用飞行模式然后恢复应用程序时,侦听器无法按要求工作。

它不会检测到没有互联网访问,即使它确实检测到当应用程序从后台恢复且未启用飞行模式时互联网访问何时可用。

我做错了什么? 从后台恢复应用程序时如何检测当前网络状态?

my current android application has a requirement to inform the user when internet access has been lost during a user session

i employ the following callback listener:-

@OptIn(DelicateCoroutinesApi::class)
class ConnectivityListener @Inject constructor() : CoroutineScope by GlobalScope, ConnectivityManager.NetworkCallback() {

    private var backgroundStateJob: Job? = null
    private val internalSharedWorkState = MutableSharedFlow<BackgroundState>(replay = 1, extraBufferCapacity = 7, onBufferOverflow = BufferOverflow.DROP_OLDEST)
    private val sharedWorkScheduleState: SharedFlow<BackgroundState> = internalSharedWorkState

    override fun onBlockedStatusChanged(network: Network, blocked: Boolean) {
        Timber.e( "onBlockedStatusChanged() called with: network = $network, blocked = $blocked")
    }
    override fun onLosing(network: Network, maxMsToLive: Int) {
        Timber.e( "onLosing() called with: network = $network, maxMsToLive = $maxMsToLive")
    }
    override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
        Timber.e( "onCapabilitiesChanged() called with: network = $network, networkCapabilities = $networkCapabilities")
    }
    override fun onLinkPropertiesChanged(network: Network, linkProperties: LinkProperties) {
        Timber.e( "onLinkPropertiesChanged() called with: network = $network, linkProperties = $linkProperties")
    }
    override fun onUnavailable() {
        Timber.e( "onUnavailable() called")
    }

    override fun onAvailable(network: Network) {
        Timber.e("onAvailable() called with: network = $network")
        backgroundStateJob?.cancel()
        backgroundStateJob = launch(Dispatchers.IO) {
            internalSharedWorkState.emit(BackgroundState.Connected())
        }
    }

    override fun onLost(network: Network) {
        Timber.e("onLost() called with: network = $network")
        backgroundStateJob?.cancel()
        backgroundStateJob = launch(Dispatchers.IO) {
            internalSharedWorkState.emit(BackgroundState.Disconnected())
        }
    }

    fun stateFlow(): SharedFlow<BackgroundState> {
        return sharedWorkScheduleState
    }
}

this listener is employed within my base activity as follow:-

private val networkRequest = NetworkRequest.Builder()
    .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
    .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
    .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
    .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
    .build()

...

 override fun onResume() {
        Timber.e("onResume() called")
        super.onResume()
        val connectivityManager = this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        connectivityManager.registerNetworkCallback(networkRequest, connectivityListener)

    }

    override fun onPause() {
        Timber.e("onPause() called")
        super.onPause()
        val connectivityManager = this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        connectivityManager.unregisterNetworkCallback(connectivityListener)
    }

the listener works as expected while the application is in the foreground and reliable informs the user on the current network status whenever internet access is lost.

the listener also works fine when i exit the application, it goes into the background and is subsequently resumed. the listener successfully reports i have internet access.

however the listener does not work as required when i put the application into the background, enable airplane mode then resume the application.

it does not detect that there is no internet access, even though it does detect when internet access is available when the app is resumed from the background and airplane mode is not enabled.

what am i doing wrong?
how can i detect the current network status when resuming my application from the background?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

煞人兵器 2025-01-16 09:51:52

来实现所需的结果

我设法通过添加第二个网络回调(如下所示)并使用 requestNetwork() 超时

override fun onResume() {
    super.onResume()
    val connectivityManager = this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    connectivityManager.registerNetworkCallback(networkRequest, connectivityListenerMonitor)
    connectivityManager.requestNetwork(networkRequest, connectivityListener, 1000)
}

override fun onPause() {
    super.onPause()
    val connectivityManager = this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    connectivityManager.unregisterNetworkCallback(connectivityListener)
    connectivityManager.unregisterNetworkCallback(connectivityListenerMonitor)
}

当我的应用程序位于后台并且启用飞行模式时,
然后将我的应用程序带到前台,我的用户会收到没有互联网连接的通知。

i managed to achieve the desired result by adding a second

network callback as follows with a timeout by employing requestNetwork()

override fun onResume() {
    super.onResume()
    val connectivityManager = this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    connectivityManager.registerNetworkCallback(networkRequest, connectivityListenerMonitor)
    connectivityManager.requestNetwork(networkRequest, connectivityListener, 1000)
}

override fun onPause() {
    super.onPause()
    val connectivityManager = this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    connectivityManager.unregisterNetworkCallback(connectivityListener)
    connectivityManager.unregisterNetworkCallback(connectivityListenerMonitor)
}

now when my application is in the background and i enable airplane mode
then bring my application to the foreground my users are notified that there is no internet connection.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文