이번에 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에 대해서는 다음 포스팅을 통해 간단히 내용 정리를 하려고 한다.

 

 

네트워크 감지에 대한 더 좋은 솔루션이 있으면 댓글로 알려주세요! 🙌