Complete solution
Create these class in a package lets say connectivity
- interface ConnectivityProvider
import android.content.Context
import android.content.Context.CONNECTIVITY_SERVICE
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
import android.net.NetworkInfo
import android.os.Build
import androidx.annotation.RequiresApi
interface ConnectivityProvider {
interface ConnectivityStateListener {
fun onStateChange(state: NetworkState)
}
fun addListener(listener: ConnectivityStateListener)
fun removeListener(listener: ConnectivityStateListener)
fun getNetworkState(): NetworkState
@Suppress("MemberVisibilityCanBePrivate", "CanBeParameter")
sealed class NetworkState {
object NotConnectedState : NetworkState()
sealed class ConnectedState(val hasInternet: Boolean) : NetworkState() {
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
data class Connected(val capabilities: NetworkCapabilities) : ConnectedState(
capabilities.hasCapability(NET_CAPABILITY_INTERNET)
)
@Suppress("DEPRECATION")
data class ConnectedLegacy(val networkInfo: NetworkInfo) : ConnectedState(
networkInfo.isConnectedOrConnecting
)
}
}
companion object {
fun createProvider(context: Context): ConnectivityProvider {
val cm = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
ConnectivityProviderImpl(cm)
} else {
ConnectivityProviderLegacyImpl(context, cm)
}
}
}
}
abstract class ConnectivityProviderBaseImpl
abstract class ConnectivityProviderBaseImpl : ConnectivityProvider {
private val handler = Handler(Looper.getMainLooper())
private val listeners = mutableSetOf<ConnectivityStateListener>()
private var subscribed = false
override fun addListener(listener: ConnectivityStateListener) {
listeners.add(listener)
listener.onStateChange(getNetworkState()) // propagate an initial state
verifySubscription()
}
override fun removeListener(listener: ConnectivityStateListener) {
listeners.remove(listener)
verifySubscription()
}
private fun verifySubscription() {
if (!subscribed && listeners.isNotEmpty()) {
subscribe()
subscribed = true
} else if (subscribed && listeners.isEmpty()) {
unsubscribe()
subscribed = false
}
}
protected fun dispatchChange(state: NetworkState) {
handler.post {
for (listener in listeners) {
listener.onStateChange(state)
}
}
}
protected abstract fun subscribe()
protected abstract fun unsubscribe()
}
class ConnectivityProviderImpl
@RequiresApi(Build.VERSION_CODES.N)
class ConnectivityProviderImpl(private val cm: ConnectivityManager) :
ConnectivityProviderBaseImpl() {
private val networkCallback = ConnectivityCallback()
override fun subscribe() {
cm.registerDefaultNetworkCallback(networkCallback)
}
override fun unsubscribe() {
cm.unregisterNetworkCallback(networkCallback)
}
override fun getNetworkState(): NetworkState {
val capabilities = cm.getNetworkCapabilities(cm.activeNetwork)
return if (capabilities != null) {
Connected(capabilities)
} else {
NotConnectedState
}
}
private inner class ConnectivityCallback : NetworkCallback() {
override fun onCapabilitiesChanged(network: Network, capabilities: NetworkCapabilities) {
dispatchChange(Connected(capabilities))
}
override fun onLost(network: Network) {
dispatchChange(NotConnectedState)
}
}
}
- class ConnectivityProviderLegacyImpl
@Suppress("DEPRECATION")
class ConnectivityProviderLegacyImpl(
private val context: Context,
private val cm: ConnectivityManager
) : ConnectivityProviderBaseImpl() {
private val receiver = ConnectivityReceiver()
override fun subscribe() {
context.registerReceiver(receiver, IntentFilter(CONNECTIVITY_ACTION))
}
override fun unsubscribe() {
context.unregisterReceiver(receiver)
}
override fun getNetworkState(): NetworkState {
val activeNetworkInfo = cm.activeNetworkInfo
return if (activeNetworkInfo != null) {
ConnectedLegacy(activeNetworkInfo)
} else {
NotConnectedState
}
}
private inner class ConnectivityReceiver : BroadcastReceiver() {
override fun onReceive(c: Context, intent: Intent) {
// on some devices ConnectivityManager.getActiveNetworkInfo() does not provide the correct network state
// https://issuetracker.google.com/issues/37137911
val networkInfo = cm.activeNetworkInfo
val fallbackNetworkInfo: NetworkInfo? = intent.getParcelableExtra(EXTRA_NETWORK_INFO)
// a set of dirty workarounds
val state: NetworkState =
if (networkInfo?.isConnectedOrConnecting == true) {
ConnectedLegacy(networkInfo)
} else if (networkInfo != null && fallbackNetworkInfo != null &&
networkInfo.isConnectedOrConnecting != fallbackNetworkInfo.isConnectedOrConnecting
) {
ConnectedLegacy(fallbackNetworkInfo)
} else {
val state = networkInfo ?: fallbackNetworkInfo
if (state != null) ConnectedLegacy(state) else NotConnectedState
}
dispatchChange(state)
}
}
}
Usage:- Home Activity
class HomeActivity : BaseActivity(), ConnectivityProvider.ConnectivityStateListener {
val provider: ConnectivityProvider by lazy { ConnectivityProvider.createProvider(this@HomeActivity) }
override fun onStart() {
super.onStart()
provider.addListener(this)
}
override fun onStop() {
super.onStop()
provider.removeListener(this)
}
override fun onStateChange(state: ConnectivityProvider.NetworkState) {
val hasInternet = state.hasInternet()
}
companion object {
fun ConnectivityProvider.NetworkState.hasInternet(): Boolean {
return (this as? ConnectivityProvider.NetworkState.ConnectedState)?.hasInternet == true
}
}
on button click or any api call
if(provider.getNetworkState().hasInternet()){
// do work
}
}
if you want to use check internet in fragments of home activities
if ((activity as HomeActivity).provider.getNetworkState().hasInternet()) {
// api call
}