Android
Android) BroadcastReciever와 LiveData로 실시간 네트워크 연결 감지하기
가짜 개발자
2022. 1. 17. 19:23
NetworkInfo
class NetworkManager(private val context : Context) {
fun isOnline(): Boolean {
val connMgr = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val networkInfo: NetworkInfo? = connMgr.activeNetworkInfo
return networkInfo?.isConnected == true
}
}
- 기존에 네트워크 연결 상태를 감지하는 위와 같은 코드가 많이 사용됩니다.
- activeNetworkInfo(getActiveNetworkInfo()) 메서드를 통해 처음 연결된 네트워크 인터페이스를 찾아서 이를 나타내는 NetworkInfo 인스턴스를 반환하거나 연결된 인터페이스가 없거나 사용 불가인 경우 null을 반환합니다.
- 단점은 실시간으로 네트워크 연결 상태를 감지할 수 없습니다. 해당 코드가 호출되는 시점에서만 체크가 되어, 중간에 인터넷 연결이 끊어진다면 체크할 수 없습니다.
- 또한, deprecated 되었습니다.
BroadcastReceiver + LiveData
- ViewModel에서는 Context 사용을 지양해야 합니다.
- 그래서 LiveData로 네트워크 연결을 감지하여 그 값을 ViewModel에 전달하는 방법을 택했습니다.
class ConnectivityWatcher(
private val context: Context
) : LiveData<Boolean>() {
private lateinit var networkCallback: ConnectivityManager.NetworkCallback
private lateinit var broadcastReceiver: BroadcastReceiver
override fun onActive() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val cm = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
networkCallback = createNetworkCallback()
cm.registerDefaultNetworkCallback(networkCallback)
} else {
val intentFilter = IntentFilter(CONNECTIVITY_ACTION)
broadcastReceiver = createBroadcastReceiver()
context.registerReceiver(broadcastReceiver, intentFilter)
}
}
override fun onInactive() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val cm = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
cm.unregisterNetworkCallback(networkCallback)
} else {
context.unregisterReceiver(broadcastReceiver)
}
}
private fun createNetworkCallback() = object : ConnectivityManager.NetworkCallback() {
@RequiresApi(Build.VERSION_CODES.M)
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities
) {
val isInternet = networkCapabilities.hasCapability(NET_CAPABILITY_INTERNET)
val isValidated = networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)
postValue(isInternet && isValidated)
}
override fun onLost(network: Network) {
postValue(false)
}
}
private fun createBroadcastReceiver() = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val isNoConnectivity = intent?.extras?.getBoolean(EXTRA_NO_CONNECTIVITY) ?: true
postValue(!isNoConnectivity)
}
}
}
- BroadcastReceiver의 서브클래스인 NetworkReceiver로 네트워크의 연결이 변경되면 NetworkReceiver에서 CONNECTIVITY_ACTION을 활용해 현재 네트워크 상태를 가져와 그 값을 LiveData로 반환합니다.
- LiveData의 onActive, onInActive 상태에 NetworkCallback의 등록 및 해제를 시켜줍니다.
- NetworkCallback은 onAvailable, onLost, onLinkPropertiesChanged, onCapabilitiesChanged, onLosing 등의 메서드를 제공합니다.
- 콜백을 등록 후 registerDefaultNetworkCallback() 또는 registerNetworkCallback()을 사용할 수 있습니다.
- 전자는 네트워크를 대상으로 하도록 미리 정의된 반면 후자는 추가 설정이 필요하지만 더 고급 기능을 제공합니다.
※ 하지만 이 방법은 애매한 연결을 감지하지 못합니다. 네트워크의 연결이 불안정하거나 연결이 되려다 말았다 하는 상황 등..
Usage
// ViewModel
val isNetworkAvailable = MutableLiveData<Boolean>()
// Activity
ConnectivityWatcher(this).observe(this) { connection ->
viewModel.isNetworkAvailable.value = connection
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
})
반응형