0

Trying to listen to a Connection call back using Live Data. The Callbacks "onAvailable" and "onLost" are fired, but the "postValue" inside the ViewModel is not fired. It is first only once when the AppViewModel is initialized and the init is called only once. When I move the postData outside the network callbacks, it fires. Any help is appreciated.

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)

In Activity, this is how View model is initialized. The log below is called only once for the first time

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

Kikki
  • 496
  • 1
  • 10
  • 17
  • Seems there is nothing wrong with the code. Can you help to attach more complete code on `registerDefaultNetworkCallback()` and on observe `wifiStatusListener` in the activity? – Putra Nugraha Nov 16 '21 at 01:59

2 Answers2

1

You should observe the change of connectivity in Activity or Fragment. Then in each call back for the changes, you pass your callback from ViewModel to handle this. And you don't need to use the wifiStatusListener to observe change. Just get the property inside the callback to handle.

Notice that you should not pass the application context to the ViewModel. Just use current context in the Activity.

hieuwu
  • 31
  • 1
  • 6
  • I understand what you are saying, but do you know why the postData is not triggered inside the Network Change callbacks. Thanks. – Kikki Nov 16 '21 at 01:02
  • I had also created a class extending the LiveData, still the postData won't fire inside the network callbacks. – Kikki Nov 16 '21 at 01:05
  • Did you try the `setValue()` instead of the `postValue()`. The postData is triggered, but in background thread. Reference here: https://stackoverflow.com/questions/51299641/difference-of-setvalue-postvalue-in-mutablelivedata – hieuwu Nov 16 '21 at 01:21
  • I tried both. didn't work. – Kikki Nov 16 '21 at 03:48
  • Just discovered an artical that you can refer : https://medium.com/@kiitvishal89/android-listening-to-connectivity-changes-the-correct-way-a614f0d6d2af – hieuwu Nov 18 '21 at 14:11
1

If your ViewModel is using Context in any form I typically make the ViewModel follow along the AndroidLifeCycle instead of storing Context in the 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();
}

You could also store the ConnectivityManager in the Activity/Fragment and just pass it instead of context but don't store it in the ViewModel.

Dharman
  • 30,962
  • 25
  • 85
  • 135
avalerio
  • 2,072
  • 1
  • 12
  • 11
  • Thanks for the answer. The Problem here is postData not firing from ViewModel. Any idea why it didn't fire in Network callback in the View Model? – Kikki Nov 16 '21 at 13:01
  • How are you determining that the events are not firing? Are you connecting/disconnecting to wifi or a cellular network? My answer was more of a fix to stop storing context inside a static resource (ie ViewModel) which could cause problems. It seems the problem you are having was not caused by that. – avalerio Nov 16 '21 at 14:04
  • I am connecting and disconnecting the wifi and the callbacks are firing, but the postValue is not firing after the first time. – Kikki Nov 16 '21 at 16:15
  • If your doing this from anything other than an `Activity` try swapping the lifecycle owner of the `ViewModel` to the `Activity` `ViewModelProvider(requireActivity()).get(AppViewModel::class.java)` – avalerio Nov 17 '21 at 21:00