0

In my application I want check internet connection and for this I write below codes.
But when before run application and disconnect internet, not call checked internet code!
Just when internet connection is connected and run application with connected internet then disconnect internet show internet is connect or disconnect!

Internet connection class:

class NetworkConnectivity @Inject constructor(private val manager: ConnectivityManager, private val request: NetworkRequest) : ConnectivityStatus {
    override fun observe(): Flow<Boolean> {
        return callbackFlow {
            val callback = object : ConnectivityManager.NetworkCallback() {
                override fun onAvailable(network: Network) {
                    super.onAvailable(network)
                    launch { send(true) }
                }

                override fun onLost(network: Network) {
                    super.onLost(network)
                    launch { send(false) }
                }
            }

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                manager.registerDefaultNetworkCallback(callback)
            } else {
                manager.registerNetworkCallback(request, callback)
            }
            awaitClose {
                manager.unregisterNetworkCallback(callback)
            }
        }
    }
}

ViewModel class:

@HiltViewModel
class DetailViewModel @Inject constructor(private val repository: MainRepository) : ViewModel() {
    @Inject
    lateinit var networkConnectivity: NetworkConnectivity    

    val detailData = MutableLiveData<NetworkRequest<ResponseDetailPage>>()
    fun callDetailApi(id: Int, apiKey: String) = viewModelScope.launch {
        Log.e("DetailLog","ViewModel 1")
        networkConnectivity.observe().collect {
            if (it) {
                Log.e("DetailLog","ViewModel 2")
                detailData.value = NetworkRequest.Loading()
                //Response
                val response = repository.remote.recipeInformation(id, apiKey)
                detailData.value = NetworkResponse(response).generalNetworkResponse()
            } else {
                Log.e("DetailLog","ViewModel 3")
                detailData.value = NetworkRequest.Error("No internet connection")
            }
        }
    }
}

After run application (when internet is disconnected) just show ViewModel 1 log in logcat!

Why not checked internet when start application with disconnected mode?

Dr.KeyOk
  • 608
  • 1
  • 6
  • 13
  • To fix this issue, you can move the call to the collect() function outside of the viewModelScope.launch block, so that it is called when the DetailViewModel is created. This will cause the callbackFlow to start emitting values as soon as the DetailViewModel is created, and it will continue to emit values whenever the network connectivity status changes. – Usama Altaf Jan 05 '23 at 12:15
  • @UsamaAltaf , Thanks my friend. Can you send to me code for this? for see this and understand your mean. please – Dr.KeyOk Jan 05 '23 at 12:17

1 Answers1

2

I'm using this function to check for internet connectivity:

fun isInternetAvailable(context: Context): Boolean {
        var result = false
        val connectivityManager =
                context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val networkCapabilities = connectivityManager.activeNetwork ?: return false
            val actNw =
                    connectivityManager.getNetworkCapabilities(networkCapabilities) ?: return false
            result = when {
                actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
                actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
                actNw.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
                else -> false
            }
        } else {
            connectivityManager.run {
                connectivityManager.activeNetworkInfo?.run {
                    result = when (type) {
                        ConnectivityManager.TYPE_WIFI -> true
                        ConnectivityManager.TYPE_MOBILE -> true
                        ConnectivityManager.TYPE_ETHERNET -> true
                        else -> false
                    }

                }
            }
        }
        return result
    }

If you target SDK23+, you can remove build version check.

Here's how I call this function in my viewmodel:

private val _internetIsAvailable = MutableLiveData<Boolean?>()
    val extInternetAvailable: LiveData<Boolean?> get() = _internetIsAvailable
    private val _loadStatus = MutableLiveData<LoadStatus>()
    val extLoadStatus: LiveData<LoadStatus> get() = _loadStatus

    init {
        // runs every time VM is created (not view created)
        viewModelScope.launch {
            _loadStatus.value = LoadStatus.LOADING
            _internetIsAvailable.value = NetworkChecker(app).isInternetAvailable()
            _loadStatus.value = LoadStatus.DONE
        }
    }

In fragments:

private fun observeInternetAvailability() {
        mainVM.extInternetAvailable.observe(this) { intAvailable ->
            Logger.d("Internet is $intAvailable")
            if (intAvailable == false) {
                ToastUtils.updateWarning(this, getString(R.string.no_internet))
                showLoading(true)
            }
        }
    }
Neone
  • 482
  • 1
  • 9
  • 21
  • I use your code, but your code just run once! when change connection does not call **observeInternetAvailability** in fragment – Dr.KeyOk Jan 05 '23 at 16:09
  • You could implement runnable with handler to run that function every X seconds https://stackoverflow.com/a/9159972/1818596 or check broadcast events https://stackoverflow.com/q/25678216/1818596 – Neone Jan 06 '23 at 17:12