Connectivity live data

Monitor network connectivity, and show a SnackBar when the connection is lost.

internal sealed class ConnectivityMonitor(
    protected val connectivityManager: ConnectivityManager
) {

    protected var callbackFunction: ((Boolean) -> Unit) = {}

    abstract fun startListening(callback: (Boolean) -> Unit)
    abstract fun stopListening()

    @TargetApi(Build.VERSION_CODES.N)
    private class NougatConnectivityMonitor(connectivityManager: ConnectivityManager) :
        ConnectivityMonitor(connectivityManager) {

        private val networkCallback = object : ConnectivityManager.NetworkCallback() {
            override fun onAvailable(network: Network) {
                super.onAvailable(network)
                callbackFunction(true)
            }

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

        override fun startListening(callback: (Boolean) -> Unit) {
            callbackFunction = callback
            callbackFunction(false)
            connectivityManager.registerDefaultNetworkCallback(networkCallback)
        }

        override fun stopListening() {
            connectivityManager.unregisterNetworkCallback(networkCallback)
            callbackFunction = {}
        }
    }

    @Suppress("Deprecation")
    private class LegacyConnectivityMonitor(
        private val context: Context,
        connectivityManager: ConnectivityManager
    ) : ConnectivityMonitor(connectivityManager) {

        private val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)

        private val isNetworkConnected: Boolean
            get() = connectivityManager.activeNetworkInfo?.isConnected == true

        override fun startListening(callback: (Boolean) -> Unit) {
            callbackFunction = callback
            callbackFunction(isNetworkConnected)
            context.registerReceiver(receiver, filter)
        }

        override fun stopListening() {
            context.unregisterReceiver(receiver)
            callbackFunction = {}
        }

        private val receiver = object : BroadcastReceiver() {
            override fun onReceive(context: Context, intent: Intent) {
                callbackFunction(isNetworkConnected)
            }
        }
    }

    companion object {
        fun getInstance(context: Context): ConnectivityMonitor {
            val connectivityManager =
                context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                NougatConnectivityMonitor(
                    connectivityManager
                )
            } else {
                LegacyConnectivityMonitor(
                    context,
                    connectivityManager
                )
            }
        }
    }
}
enum class ConnectivityState {
    Connected,
    Disconnected
}

class ConnectivityLiveData :
    MutableLiveData<ConnectivityState>(), KoinComponent {

    private val connectionMonitor: ConnectivityMonitor by inject()

    override fun onActive() {
        super.onActive()
        connectionMonitor.startListening(::setConnected)
    }

    override fun onInactive() {
        connectionMonitor.stopListening()
        super.onInactive()
    }

    private fun setConnected(isConnected: Boolean) =
        postValue(if (isConnected) ConnectivityState.Connected else ConnectivityState.Disconnected)
}

Usage

Sample usage using Koin DI:

class MainActivity : AppCompatActivity() {
    val connectivity: ConnectivityLiveData by inject()

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        connectivity.observeForever { state ->
            if (state != ConnectivityState.Connected) {
                showSnackbar(R.string.no_internet)
            } else {
                hideSnackbar()
            }
        }
    }

    fun showSnackbar(error: Int) {
        snackbar =
            Snackbar.make(activity_parent, error, Snackbar.LENGTH_INDEFINITE)
        snackbar?.let {
            snackbar!!.setAction(R.string.label_Ok) { snackbar!!.dismiss() }
            snackbar!!.show()
        }
    }

    fun hideSnackbar() {
        if (snackbar != null) {
            if (snackbar!!.isShown) snackbar!!.dismiss()
        }
    }
}