-
-
Save marenovakovic/9466bfc1b765e06e1b3600efbc4da2f8 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() | |
} | |
} |
I'm just starting to tinker with this (and Compose). With latest studio and up-to-date implementations I have a error I don't know how to fix.
In the construction of the ViewModel via the Factory, I received an error pinned on the "object" line which reads:
Inheritance from an interface with '@JvmDefault' members is only allowed with -Xjvm-default option
Have you seen this and do you have any suggestions on what I should do to fix it?
thanks,
steve
@sralpert Better to ask that on Stackoverflow but maybe this helps: https://stackoverflow.com/questions/70992947/how-do-i-resolve-error-message-inheritance-from-an-interface-with-jvmdefault
@sralpert I will check it out
@sralpert sorry for late response. I can't reproduce that, no issues when I try to implement it. best is to follow that StackOverflow link
@Drjacky sorry. Where did you put the line connectivityManager.requestNetwork(request, networkStatusCallback, 1000)
? Thank you very much
...
val request = NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build()
connectivityManager.registerNetworkCallback(request, callback)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
connectivityManager.requestNetwork(request, callback, 1000) //THISSSS
}
awaitClose {
connectivityManager.unregisterNetworkCallback(callback)
}
}
.distinctUntilChanged()
Can have checking connection in kotlin multiplatform instead of seperate android and ios?
@hafiz013 sure you can.
there are libraries like:
https://github.com/jordond/connectivity
and
https://github.com/ln-12/multiplatform-connectivity-status
The same issue as @PatricioIN
It doesn't trigger for the first time. Although, I use this
collectIn
directly to collect the emission:but when I change the wifi/data, it works!
Update:
I followed what you did and still, it doesn't work when the internet is already disconnected.
Update:
I had to add
connectivityManager.requestNetwork(request, networkStatusCallback, 1000)
too, now it works 🎉