이번에 Lifecycle
을 Base project에 도입하면서, 네트워크 연결 상태 관련 로직을 수정했다.
대부분의 앱들은 인터넷을 이용한 서비스를 한다.
그렇기 때문에, 앱에서는 인터넷 사용을 위해 지속적으로 네트워크 상태를 체크할 필요가 있다.
안드로이드에서는 이 기능을 구현하기 위해서 ConnectivityManager
라는 클래스를 제공한다.
실시간 네트워크 상태 감지
먼저 ConnectivityManager
를 선언하고,
val connectivityManager = lifecycleOwner.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
네트워크를 감지할 Capabilities
를 선언한다.
private val networkRequest: NetworkRequest = NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build()
☝️ NetworkCapabilities
에는 다양한 타입들을 지원한다.
그리고 registerNetworkCallback
메소드를 통해 실시간 감지 서비스를 등록한다.
fun enable() {
connectivityManager.registerNetworkCallback(networkRequest, this)
}
ConnectivityManager.NetworkCallback()
을 Extends 하면 onAvailable
, onLost
Override 메소드들이 있는데, 이 메소드들을 통해 실시간으로 네트워크 상태를 감지할 수 있다.
/** Network가 Available 상태이면 Call **/
override fun onAvailable(network: Network) {
super.onAvailable(network)
DLog.i("networkAvailable")
}
/** Network가 Available 상태에서 Unavailable로 변경되면 Call **/
override fun onLost(network: Network) {
super.onLost(network)
DLog.i("networkUnavailable")
}
최초 앱 실행시 네트워크 체크
NetworkCallback
을 통한 실시간 상태 체크는 앱이 실행되고 난 후 연결 상태에 따라 처리가 되기 때문에,
사용자가 처음부터 네트워크가 연결되지 않은 상태에서 앱을 실행했다면, 네트워크 미연결 상태에 대해 감지하지는 못 한다.
다음과 같이 getActivityNetwork
메소드를 사용해서 최초 앱 실행시 Null 체크를 하면 이 기능을 구현할 수 있다.
fun initNetworkCheck() {
if(connectivityManager.activeNetwork != null) {
// 네트워크가 연결되어 있음
} else {
// 네트워크가 연결되어 있지 않음
}
}
[22-04-12] 수정사항
@OnLifecycleEvent()가 Deprecated되어서 LifecycleObserver 대신 DefaultLifecycleObserver를 활용한다.
다음은 구현한 NetworkStateMonitor
클래스의 전문이다.
class NetworkStateMonitor(private val lifecycleOwner: AppCompatActivity):
ConnectivityManager.NetworkCallback(),
DefaultLifecycleObserver {
private val connectivityManager = lifecycleOwner.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
/** Network를 감지할 Capabilities 선언 **/
private val networkRequest: NetworkRequest = NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build()
/** 네트워크 상태 체크 **/
fun initNetworkCheck() {
val activeNetwork = connectivityManager.activeNetwork
if(activeNetwork != null) {
DLog.e("네트워크 연결되어 있음")
} else {
DLog.e("네트워크 연결되어 있지않음")
}
}
/** Network 모니터링 서비스 시작 **/
fun enable() {
check(lifecycleOwner.lifecycle.currentState.isAtLeast(Lifecycle.State.INITIALIZED))
connectivityManager.registerNetworkCallback(networkRequest, this)
}
/* Network 모니터링 서비스 해제
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun disable() {
connectivityManager.unregisterNetworkCallback(this)
lifecycleOwner.lifecycle.removeObserver(this)
} */
override fun onCreate(owner: LifecycleOwner) {
super.onCreate(owner)
enable()
initNetworkCheck()
}
override fun onDestroy(owner: LifecycleOwner) {
super.onDestroy(owner)
// Network 모니터링 서비스 종료
connectivityManager.unregisterNetworkCallback(this)
lifecycleOwner.lifecycle.removeObserver(this)
}
/** Network가 Available 상태이면 Call **/
override fun onAvailable(network: Network) {
super.onAvailable(network)
DLog.i("networkAvailable()")
}
/** Network가 Available 상태에서 Unavailable로 변경되면 Call **/
override fun onLost(network: Network) {
super.onLost(network)
DLog.i("networkUnavailable()")
}
}
나의 경우엔 BaseActivity
에서 이 서비스를 시작하는 로직을 넣었다.
이렇게 하는 이유는 새로 만들어지는 액티비티마다 네트워크 상태를 감지하는 서비스 시작을 구현해야 하는데,
이 로직을 BaseActivity
에 구현하면 일일히 넣어줄 필요가 없기 때문에, 보일러 플레이트 코드를 방지할 수 있다.
@SuppressLint("Registered")
open class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Network 상태 모니터 서비스 라이프사이클 등록 및 시작
val networkStatusMonitor = NetworkStateMonitor(this)
lifecycle += networkStatusMonitor
}
}
☝️ Lifecycle
을 사용해서 구현했는데, Lifecycle
에 대해서는 다음 포스팅을 통해 간단히 내용 정리를 하려고 한다.
네트워크 감지에 대한 더 좋은 솔루션이 있으면 댓글로 알려주세요! 🙌