Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Nikhil-z/476129a7d7a383762857307339cfbfeb to your computer and use it in GitHub Desktop.
Save Nikhil-z/476129a7d7a383762857307339cfbfeb to your computer and use it in GitHub Desktop.
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
val networkStatus = callbackFlow<NetworkStatus> {
val networkStatusCallback = object : ConnectivityManager.NetworkCallback() {
override fun onUnavailable() {
println("onUnavailable")
offer(NetworkStatus.Unavailable)
}
override fun onAvailable(network: Network) {
println("onAvailable")
offer(NetworkStatus.Available)
}
override fun onLost(network: Network) {
println("onLost")
offer(NetworkStatus.Unavailable)
}
}
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()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment