Forked from marenovakovic/NetworkStatusTracker_full.kt
Last active
October 23, 2023 16:56
-
-
Save gsrathoreniks/26ad123653b3e3115a00d4feedaabdbe to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Context | |
import android.net.ConnectivityManager | |
import android.net.Network | |
import android.net.NetworkCapabilities | |
import android.net.NetworkRequest | |
import android.os.Bundle | |
import android.widget.TextView | |
import androidx.appcompat.app.AppCompatActivity | |
import androidx.lifecycle.ViewModel | |
import androidx.lifecycle.ViewModelProvider | |
import kotlinx.coroutines.Dispatchers | |
import kotlinx.coroutines.FlowPreview | |
import kotlinx.coroutines.channels.awaitClose | |
import kotlinx.coroutines.flow.Flow | |
import kotlinx.coroutines.flow.callbackFlow | |
import kotlinx.coroutines.flow.distinctUntilChanged | |
import kotlinx.coroutines.flow.flatMapConcat | |
import kotlinx.coroutines.flow.map | |
class MainActivity : AppCompatActivity() { | |
private val viewModel: NetworkStatusViewModel by lazy { | |
ViewModelProvider( | |
this, | |
object : ViewModelProvider.Factory { | |
override fun <T : ViewModel?> create(modelClass: Class<T>): T { | |
val networkStatusTracker = NetworkStatusTracker(this@MainActivity) | |
return NetworkStatusViewModel(networkStatusTracker) as T | |
} | |
}, | |
).get(NetworkStatusViewModel::class.java) | |
} | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
setContentView(R.layout.activity_main) | |
viewModel.state.observe(this) { state -> | |
findViewById<TextView>(R.id.textView).text = when (state) { | |
MyState.Fetched -> "Fetched" | |
MyState.Error -> "Error" | |
} | |
} | |
} | |
} | |
sealed class MyState { | |
object Fetched : MyState() | |
object Error : MyState() | |
} | |
class NetworkStatusViewModel( | |
networkStatusTracker: NetworkStatusTracker, | |
) : ViewModel() { | |
val state = | |
networkStatusTracker.networkStatus | |
.map( | |
onAvailable = { MyState.Fetched }, | |
onUnavailable = { MyState.Error }, | |
) | |
.asLiveData(Dispatchers.IO) | |
} | |
sealed class NetworkStatus { | |
object Available : NetworkStatus() | |
object Unavailable : NetworkStatus() | |
} | |
class NetworkStatusTracker(context: Context) { | |
private val connectivityManager = | |
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager | |
private val validNetworks: MutableSet<Network> = HashSet() | |
val networkStatus = callbackFlow<NetworkStatus> { | |
val networkStatusCallback = object : ConnectivityManager.NetworkCallback() { | |
override fun onUnavailable() { | |
validNetworks.remove(network) | |
if(validNetworks.size==0) | |
trySend(NetworkStatus.Unavailable).isSuccess | |
} | |
override fun onAvailable(network: Network) { | |
validNetworks.add(network) | |
trySend(NetworkStatus.Available).isSuccess | |
} | |
override fun onLost(network: Network) { | |
validNetworks.remove(network) | |
if(validNetworks.size==0) | |
trySend(NetworkStatus.Unavailable).isSuccess | |
} | |
} | |
val request = NetworkRequest.Builder() | |
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) | |
.build() | |
connectivityManager.registerNetworkCallback(request, networkStatusCallback) | |
awaitClose { | |
connectivityManager.unregisterNetworkCallback(networkStatusCallback) | |
} | |
} | |
.distinctUntilChanged() | |
} | |
@FlowPreview | |
inline fun <Result> Flow<NetworkStatus>.map( | |
crossinline onUnavailable: suspend () -> Result, | |
crossinline onAvailable: suspend () -> Result, | |
): Flow<Result> = map { status -> | |
when (status) { | |
NetworkStatus.Unavailable -> onUnavailable() | |
NetworkStatus.Available -> onAvailable() | |
} | |
} | |
@FlowPreview | |
inline fun <Result> Flow<NetworkStatus>.flatMap( | |
crossinline onUnavailable: suspend () -> Flow<Result>, | |
crossinline onAvailable: suspend () -> Flow<Result>, | |
): Flow<Result> = flatMapConcat { status -> | |
when (status) { | |
NetworkStatus.Unavailable -> onUnavailable() | |
NetworkStatus.Available -> onAvailable() | |
} | |
} |
Yeah I understood that but the network variable in onUnavailable method is
undefined
…On Wed, 31 Aug, 2022, 3:59 pm Gajendra Singh Rathore, < ***@***.***> wrote:
***@***.**** commented on this gist.
------------------------------
We've multiple source for network, if we don't remove valid network in
onUnavailable then if only mobile data is active and wifi became
unavailable, then it will trigger that there's no network available.
The above code takes care of that, it only emit the un-available state
when there's no network in either mobile or wifi.
—
Reply to this email directly, view it on GitHub
<https://gist.github.com/26ad123653b3e3115a00d4feedaabdbe#gistcomment-4285548>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ATJQ4NWUZ7UEI7YY7SF26DTV34XZLANCNFSM6AAAAAAQBDEPRU>
.
You are receiving this because you commented.Message ID:
***@***.***>
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
We've multiple source for network, if we don't remove valid network in onUnavailable then if only mobile data is active and wifi became unavailable, then it will trigger that there's no network available.
The above code takes care of that, it only emit the un-available state when there's no network in either mobile or wifi.