본문 바로가기
Android & Kotlin/Android

[Android kotlin] 네트워크 메니저로 사용자 경험 개선하기 (Connectivity Manager)

by 말린밴댕이_공부 2024. 1. 2.
반응형

네트워크 설정 공식 레퍼런스

https://developer.android.com/training/basics/network-ops/reading-network-state?hl=ko

 

네트워크 상태 읽기  |  Connectivity  |  Android Developers

네트워크 상태 읽기 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Android에서는 앱이 연결의 동적 변경사항을 학습할 수 있습니다. 다음 클래스를 사용하여

developer.android.com

 

우리는 앱을 사용하다 보면 네트워크의 연결에 대한 알림을 주는 것을 많이 볼 수 있다.

네트워크 연결 상태를 관리하고 모니터링하여보다 사용자에게 편리함을 제공해주고자 이 부분에 대해서 공략을 해보고자 하였습니다.

 

네트워크 권한 설정부터 진행을 하도록 하겠습니다.

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

 

 

  • <uses-permission android:name="android.permission.INTERNET" />
  • 이 권한은 앱이 인터넷을 사용할 수 있도록 허용합니다.
  • 인터넷 권한이 필요한 경우, 앱은 네트워크를 통해 데이터를 다운로드하거나 업로드하고 웹 서비스와 통신할 수 있습니다.
  • <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  • 이 권한은 앱이 네트워크 상태에 대한 정보에 접근할 수 있도록 허용합니다.
  • 네트워크 상태를 확인할 때 사용되며, 예를 들어 현재 기기가 Wi-Fi에 연결되어 있는지, 데이터 네트워크를 사용할 수 있는지 등을 확인할 수 있습니다.

 

기본적인 이해 (네트워크 순간 상태 가져오기)

val connectivityManager = getSystemService(ConnectivityManager::class.java)

val currentNetwork = connectivityManager.getActiveNetwork()

val caps = connectivityManager.getNetworkCapabilities(currentNetwork)
val linkProperties = connectivityManager.getLinkProperties(currentNetwork)

 

기본 네트워크의 참조를 가져와 네트워크 정보를 요청하여 알아보려 합니다.


`NetworkCapabilities` 및 `LinkProperties` 객체는 네트워크에 관해 시스템이 알고 있는 모든 속성 정보를 제공합니다.

 

네트워크 이벤트 수신대기

connectivityManager.registerDefaultNetworkCallback(object : ConnectivityManager.NetworkCallback() {
    override fun onAvailable(network : Network) {
        Log.e(TAG, "The default network is now: " + network)
    }

    override fun onLost(network : Network) {
        Log.e(TAG, "The application no longer has a default network. The last default network was " + network)
    }

    override fun onCapabilitiesChanged(network : Network, networkCapabilities : NetworkCapabilities) {
        Log.e(TAG, "The default network changed capabilities: " + networkCapabilities)
    }

    override fun onLinkPropertiesChanged(network : Network, linkProperties : LinkProperties) {
        Log.e(TAG, "The default network changed link properties: " + linkProperties)
    }
})

 

`onAvailable` :  네트워크가 이용이 가능해질 때 호출

`onLost` : 네트워크가 소실 되었을 때 호출 **(디바이스가 모든 네트워크 연결을 잃었을 때 호출)**

`onCapabilitiesChanged` : 네트워크 기능이 변경되었을 때 호출

`onLinkPropertiesChanged` : 기본 네트워크의 링크 속성이 변경되었을 때 호출

`onAvailable`과 `onLost`를 공식문서의 내용을 살펴보면

네트워크 이용이 가능할 때 와 네트워크가 모든 연결을 잃었을때! 라고 하였지만 

 

네트워크 이슈(문제 사항)

연결을 하나 끊었을때나 연결이 되었을 때 호출이 되는 모습을 확인할 수 있었습니다.

 

그것에 대한 가설

  1. Wi-Fi 및 셀룰러 데이터 모두 켜져 있을 때
    • onAvailable 콜백이 호출되어 Wi-Fi 및 셀룰러 데이터가 모두 이용 가능한 상태를 나타냄
  2. Wi-Fi 또는 셀룰러 데이터 중 하나를 끌 때
    • 해당하는 onLost 콜백이 호출될 것. 기존 이용가능하던 네트워크가 소실
  3. Wi-Fi 및 셀룰러 데이터 둘 다 끌 때
    • onLost 콜백이 호출되고 네트워크 전부 소실
  4. Wi-Fi 또는 셀룰러 데이터 중 하나를 다시 켤 때
    • onAvailable 콜백이 호출되어 다시 이용 가능한 상태

즉, 어떤 연결이나 소실이 되었을때 무조건 available, lost가 호출이 된다!

위의 기본적인 내용을 토대로 **NetworkManager** 를 만들어 보았습니다.

class NetworkManager @Inject constructor(private val connectivityManager: ConnectivityManager) {

    private val _isNetworkConnected = MutableStateFlow(isInternetOn())
    val isNetworkConnected: StateFlow<Boolean> = _isNetworkConnected

    private val networkRequest = NetworkRequest.Builder()
        .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
        .build()

    private fun isInternetOn() : Boolean{
        val network = connectivityManager.activeNetwork
        val connection = connectivityManager.getNetworkCapabilities(network)

        return connection != null &&(
                connection.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
                        connection.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR))
    }

    private val networkCallback = object : ConnectivityManager.NetworkCallback() {
        override fun onAvailable(network: Network) {
            _isNetworkConnected.value = isInternetOn()
        }

        override fun onLost(network: Network) {
            _isNetworkConnected.value = isInternetOn()
        }
    }

    fun startNetwork() {
        connectivityManager.registerNetworkCallback(networkRequest, networkCallback)
    }

    fun endNetwork() {
        connectivityManager.unregisterNetworkCallback(networkCallback)
    }
}

데이터와 와이파이에 대한 state를 동시에 관찰하여 진행을 해보면 어떨까? 라는 생각으로 inInternetOn() 을 만들어 진행해보았습니다.

 

그 결과 네트워크에 대한 관찰이 정상적으로 되는 모습을 확인할 수 있습니다!

 

하지만 최종문제

가끔씩 두가지 모두 state를 관찰하지만 두개가 연결되어있는 상황에 하나의 연결을 끊었을 때 아주 짧은 시간 사이에 네트워크가 변경이 되면서 두가지가 잠시 연결이 끊기는 현상이 발견됩니다.

 

이 부분에 대해서는 알아보니 금융앱같은 경우 심도있게 다루겠지만 그런게 정말! 중요한 앱이 아니라면 이정도 까지는 아니다가 저의 결론이지만 다음에 시간이나면 이어서 고찰해보는걸로..

반응형

댓글