[Android] ConnectivityManager를 이용해 실시간 연결 여부 확인하기

윤찬·2025년 9월 30일

Android

목록 보기
31/37

특정 앱을 보면 연결이 끊기는 경우 팝업이 나오거나 연결이 안됐다는 화면이 나오는 것을 볼 수 있을 것이다.
이를 구현하기 위해서는 ConnectivityManager를 이용해 구현이 가능하다.

해당 구현 예제는 유튜브 강의를 통해 진행을 했다.

의존성 추가

[versions]
lifecycleRuntimeKtx = "2.9.4"

[libraries]
androidx-lifecycle-runtime-compose = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "lifecycleRuntimeKtx" }
androidx-lifecycle-viewmodel-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycleRuntimeKtx" }

Hilt나 koin같은 의존성 주입으로도 진행해도 되지만 간단하게 연결이 되는 여부만 판단하고 싶기 때문에 위 의존성을 추가

dependencies {
    implementation(libs.androidx.lifecycle.runtime.compose)
    implementation(libs.androidx.lifecycle.viewmodel.compose)
}

ConnectivityObserver 인터페이스 및 구현


interface ConnectivityObserver {
    val isConnected: Flow<Boolean>
}

class AndroidConnectivityObserver(
    private val context: Context
) : ConnectivityObserver {

    private val connectivityManager = context.getSystemService<ConnectivityManager>()

	//isConnected는 연결 여부를 Flow형식으로 데이터형식이 변경될 때마다 trySend로 연결 여부를 보낸다.
	//여기서 callbackFlow를 사용한 이유는 ConnectivityManager가 callback을 등록/해제해야 하고 callback에 따라 데이터를 보내야 하기 위해 사용
    override val isConnected: Flow<Boolean>
        get() = callbackFlow {
        
        	//ConnectivityManager.NetworkCallback은 안드로이드에서 네트워크 상태 변화를 감지할 때 사용됩니다.
            val callback = object : ConnectivityManager.NetworkCallback() {
            
            	//네트워크의 세부 기능(capabilities)이 바뀌었을 때 호출됩니다.
                //예를 들어 인터넷 연결이 안되다가 연결이 되는 상태로 바뀔 때
                ..
                override fun onCapabilitiesChanged(
                    network: Network,
                    networkCapabilities: NetworkCapabilities
                ) {
                    super.onCapabilitiesChanged(network, networkCapabilities)
                    //networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
                    //실제 인터넷 연결 여부 확인
                    val connected = networkCapabilities.hasCapability(
                        NetworkCapabilities.NET_CAPABILITY_VALIDATED
                    )
                    trySend(connected)
                }

				//네트워크 요청을 했는데, 아예 사용 가능한 네트워크가 없을 때 호출됩니다.
                override fun onUnavailable() {
                    super.onUnavailable()
                    trySend(false)
                }

				//이미 사용 중이던 네트워크 연결이 끊겼을 때 호출됩니다.
                override fun onLost(network: Network) {
                    super.onLost(network)
                    trySend(false)
                }

				//네트워크가 사용 가능해졌을 때 호출됩니다.
                //예: Wifi
                override fun onAvailable(network: Network) {
                    super.onAvailable(network)
                    trySend(true)
                }
            }

            connectivityManager?.registerDefaultNetworkCallback(callback)

            awaitClose {
                connectivityManager?.unregisterNetworkCallback(callback)
            }
        }
}

연결 상태 및 연결 측정 모니터링은 아래 공식 문서를 참조하면 좋을 것 같다.
https://developer.android.com/training/monitoring-device-state/connectivity-status-type?hl=ko

사실상 이 코드가 가장 중요한 코드다. 인터페이스는 아마 domain쪽에 들어갈 것 같고 AndroidConnectivityObserver는 data 모듈에서 applicationContext를 주입받아 사용하면 특정 화면에서 연결 여부를 확인하고 싶을 때 ViewModel에서 ConnectivityObserver를 주입받아서 사용하면 재사용성이 증가할 것이다.

UI에서 연결 정보 가져오기

class ConnectivityViewModel(
    private val connectivityObserver: ConnectivityObserver
) : ViewModel() {

    val isConnected = connectivityObserver.isConnected
        .stateIn(
            viewModelScope,
            SharingStarted.WhileSubscribed(5000),
            false
        )
}

hilt로 주입하거나, koin으로 주입해도 되지만 그것까지 사용할건 아니기 때문에 UI에서는 직접 factory에서 생성자 주입을 했다.

class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
        	//직접 주입
            val viewModel = viewModel<ConnectivityViewModel> {
                ConnectivityViewModel(
                    connectivityObserver = AndroidConnectivityObserver(
                    	//여기에는 applicationContext가 적합
                        context = applicationContext
                    )
                )
            }
            ConnectManagerExTheme {
                val isConnected by viewModel.isConnected.collectAsStateWithLifecycle()
                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
                    Box(
                        modifier = Modifier
                            .fillMaxSize()
                            .padding(innerPadding),
                        contentAlignment = Alignment.Center
                    ) {
                        Text(
                            text = "Connected? $isConnected"
                        )
                    }
                }
            }
        }
    }
}

실제로 동작하면 연결 상태를 끊으면 false, 다시 연결하면 true가 나오는 것을 볼 수 있다.

profile
좋은 개발자가 되기까지

0개의 댓글