在 Android 视图模型中的内部网络更改回调时 LiveData 未触发 - Kotlin

Posted

技术标签:

【中文标题】在 Android 视图模型中的内部网络更改回调时 LiveData 未触发 - Kotlin【英文标题】:LiveData not firing when Inside Network Change Callbacks in Android View Model - Kotlin 【发布时间】:2021-12-27 02:53:43 【问题描述】:

尝试使用实时数据收听连接回调。 回调“onAvailable”和“onLost”被触发,但 ViewModel 中的“postValue”没有被触发。当 AppViewModel 被初始化并且 init 只被调用一次时,它是第一次。 当我将 postData 移到网络回调之外时,它会触发。 任何帮助表示赞赏。

class AppViewModel(application: Application) : androidViewModel(application) 

    private var connectivityManager =
        application.applicationContext.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
    var wifiStatusListener = MutableLiveData<Boolean>()

    var callback: NetworkCallback =
        object : NetworkCallback() 
            override fun onAvailable(network: Network) 
                wifiStatusListener.postValue(true) // never calls.
                logI(TAG, "onAvailable $network.describeContents()")
            

            override fun onLost(network: Network) 
                wifiStatusListener.postValue(false) // never calls.
                logE(TAG, "onLost $network.describeContents()")
            
        



    init 
        logI(TAG, "View Model Initialized")
        viewModelScope.launch 
            initWiFiStatusCheckListener()
        
    
 // called from init in ViewModel
 connectivityManager.registerDefaultNetworkCallback(callback)

在 Activity 中,这就是 View 模型的初始化方式。 下面的日志第一次只调用一次

logI(TAG, "Wifi Listener $it")
 appViewModel = ViewModelProvider(this).get(AppViewModel::class.java)
 appViewModel.wifiStatusListener.observe(this, Observer 
            logI(TAG, "Wifi Listener $it")
        )     

【问题讨论】:

看来代码没有问题。您能帮忙在活动中的registerDefaultNetworkCallback() 和观察wifiStatusListener 上附加更完整的代码吗? 【参考方案1】:

您应该观察 Activity 或 Fragment 的连接性变化。然后在每次回调更改时,您从 ViewModel 传递回调来处理此问题。而且您不需要使用wifiStatusListener 来观察变化。只需获取回调内部的属性即可处理。

请注意,您不应将应用程序上下文传递给 ViewModel。只需在 Activity 中使用当前上下文。

【讨论】:

我明白你在说什么,但你知道为什么 postData 没有在 Network Change 回调中触发吗?谢谢。 我还创建了一个扩展 LiveData 的类,但 postData 仍然不会在网络回调中触发。 您是否尝试过使用setValue() 而不是postValue()。 postData 被触发,但在后台线程中。参考这里:***.com/questions/51299641/… 我都试过了。没用。 刚发现一篇文章,可以参考一下:medium.com/@kiitvishal89/…【参考方案2】:

如果您的ViewModel 以任何形式使用Context,我通常会让ViewModel 跟随AndroidLifeCycle,而不是将Context 存储在ViewModel 中。

//in ViewModel
fun onResume(context : Context)
    var connectivityManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
    connectivityManager.registerDefaultNetworkCallback(callback)

fun onPause(context : Context)
    var connectivityManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
    connectivityManager.unregisterNetworkCallback(callback)




//in Activity/Fragment
fun onResume()
    super.onResume();
    viewModel.onResume(requireContext())

fun onPause()
    viewModel.onPause(requireContext())
    super.onPause();

您也可以将ConnectivityManager 存储在Activity/Fragment 中,然后只传递它而不是上下文,但不要将它存储在ViewModel 中。

【讨论】:

感谢您的回答。这里的问题是 postData 没有从 ViewModel 触发。知道为什么它没有在视图模型的网络回调中触发吗? 您如何确定事件没有触发?您是在连接/断开 wifi 还是蜂窝网络?我的回答更多的是停止将上下文存储在可能导致问题的静态资源(即 ViewModel)中。您遇到的问题似乎不是由此引起的。 我正在连接和断开 wifi 并且回调正在触发,但 postValue 在第一次之后没有触发。 如果您不是从Activity 执行此操作,请尝试将ViewModel 的生命周期所有者交换为Activity ViewModelProvider(requireActivity()).get(AppViewModel::class.java)

以上是关于在 Android 视图模型中的内部网络更改回调时 LiveData 未触发 - Kotlin的主要内容,如果未能解决你的问题,请参考以下文章

Android - 查看子项数量更改时的侦听器/回调

Android视图动画生命周期

应用程序关闭时如何接收 Android Nougat 网络丢失的回调?

iOS - 每次显示的视图更改时回调

内部动画时的 UIScrollView 回调

如何知道 laravel 模型值是不是在保存回调时更改