일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 서비스 쓰레드 차이
- ANR이란
- 스택 자바 코드
- 플러터 설치 2022
- rxjava disposable
- 안드로이드 유닛 테스트
- 멤버변수
- 안드로이드 레트로핏 crud
- jvm이란
- 안드로이드 os 구조
- 안드로이드 유닛테스트란
- 클래스
- 스택 큐 차이
- rxjava cold observable
- Rxjava Observable
- 2022 플러터 안드로이드 스튜디오
- 안드로이드 레트로핏 사용법
- ar vr 차이
- 안드로이드 라이선스 종류
- 안드로이드 라이선스
- android ar 개발
- 서비스 vs 쓰레드
- android retrofit login
- jvm 작동 원리
- 자바 다형성
- rxjava hot observable
- 객체
- 안드로이드 유닛 테스트 예시
- 2022 플러터 설치
- 큐 자바 코드
- Today
- Total
나만을 위한 블로그
[Android] 네트워크 연결 상태를 확인하는 방법(JAVA + Kotlin) 본문
네트워크 예외처리를 하다 보면 현재 기기에 인터넷이 연결된 상태인지를 확인해야 할 수 있다.
연결된 상태면 다음 로직을 이어서 수행하거나, 연결되지 않은 상태라면 다이얼로그를 띄워서 이전 액티비티로 보낸다거나 하는 처리가 그것이다. 대부분의 상용 앱에서도 데이터 연결, 와이파이 연결을 모두 해제하면 이러한 처리가 되어 있는 걸 볼 수 있다.
이번 포스팅에선 자바와 코틀린으로 인터넷 연결 상태를 어떻게 확인하는지에 대해 포스팅하려고 한다.
주의할 것은 이 기능을 구현하는 코드의 전개 방식은 정말 다양하니 아래의 방법이 정답이 아니라는 것만 짚어두고 간다.
아래 글을 읽기 전 매니페스트에 아래의 권한이 있는지 꼭 확인한다. 없으면 추가한다.
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
먼저 자바로는 어떻게 하는지 확인해보자.
private class disconnectHandler implements Runnable
{
@Override
public void run()
{
boolean isConnected = isNetworkConnected(SplashActivity.this);
if (!isConnected)
{
AlertDialog.Builder builder = new AlertDialog.Builder(SplashActivity.this);
builder.setMessage("인터넷 연결이 원활하지 않습니다")
.setCancelable(false)
.setPositiveButton("종료", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
finishAffinity();
}
}).show();
}
else
{
.
.
.
SplashActivity.this.finish();
}
}
}
내 경우엔 핸들러를 만들고 그 안에서 네트워크 연결 상태를 확인한 다음 그 값을 변수에 저장해서 어떤 상태냐에 따라 다이얼로그가 나오거나 다음 화면으로 이동하도록 처리했다. else 블럭 안 마지막 줄의 finish()가 그것이다. 그 위의 로직들은 지금 포스팅과는 상관없는 내용들이기 때문에 없앴다.
위의 코드에서 사용된 isNetworkConnected()의 내용은 아래와 같다.
public boolean isNetworkConnected(Context context)
{
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mobile = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
NetworkInfo wifi = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
NetworkInfo wimax = manager.getNetworkInfo(ConnectivityManager.TYPE_WIMAX);
boolean bwimax = false;
if (wimax != null)
{
bwimax = wimax.isConnected();
}
if (mobile != null)
{
if (mobile.isConnected() || wifi.isConnected() || bwimax)
{
return true;
}
}
else
{
if (wifi.isConnected() || bwimax)
{
return true;
}
}
return false;
}
wimax는 흔히 4G라 불리는 네트워크에 연결할 수 있도록 하는 통신 프로토콜이다. 그래서 3G, 와이파이, 4G 상태를 모두 체크하여 연결된 상태면 true, 아니면 false를 리턴시킨다. 이 메서드를 통해 네트워크 통신 예외처리를 할 수 있다.
주의할 것은 API 28부터 ConnectivityManager.TYPE_MOBILE, TYPE_WIFI, TYPE_WIMAX 3개는 deprecated되었다.
그래서 이걸 쓰기 찜찜하다면 아래의 포스팅들을 확인하면 좋을 것 같다.
https://gist.github.com/PasanBhanu/730a32a9eeb180ec2950c172d54bb06a
https://developer.android.com/training/basics/network-ops/reading-network-state#java
https://developer.android.com/reference/android/net/NetworkCapabilities.html#hasTransport(int)
아무튼 자바로 하는 건 어떻게 하는지 대충 알았으니 이제 코틀린으로는 어떻게 만드는지 확인해보자.
먼저 클래스 하나를 만들어줘야 한다.
import android.annotation.TargetApi
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.*
import android.os.Build
import androidx.lifecycle.LiveData
class NetworkConnection(private val context: Context) : LiveData<Boolean>()
{
private var connectivityManager: ConnectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
private lateinit var networkCallback: ConnectivityManager.NetworkCallback
override fun onActive()
{
super.onActive()
updateConnection()
when
{
Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ->
{
connectivityManager.registerDefaultNetworkCallback(connectivityManagerCallback())
}
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ->
{
lollipopNetworkRequest()
}
else ->
{
context.registerReceiver(
networkReceiver,
IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
)
}
}
}
override fun onInactive()
{
super.onInactive()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
connectivityManager.unregisterNetworkCallback(connectivityManagerCallback())
} else
{
context.unregisterReceiver(networkReceiver)
}
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private fun lollipopNetworkRequest()
{
val requestBuilder = NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
connectivityManager.registerNetworkCallback(
requestBuilder.build(),
connectivityManagerCallback()
)
}
private fun connectivityManagerCallback(): ConnectivityManager.NetworkCallback
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
networkCallback = object : ConnectivityManager.NetworkCallback()
{
override fun onLost(network: Network)
{
super.onLost(network)
postValue(false)
}
override fun onAvailable(network: Network)
{
super.onAvailable(network)
postValue(true)
}
}
return networkCallback
} else
{
throw IllegalAccessError("Error")
}
}
private val networkReceiver = object : BroadcastReceiver()
{
override fun onReceive(context: Context?, intent: Intent?)
{
updateConnection()
}
}
private fun updateConnection()
{
val activeNetwork: NetworkInfo? = connectivityManager.activeNetworkInfo
postValue(activeNetwork?.isConnected == true)
}
}
이제 이 클래스를 사용해서 액티비티에서 네트워크 연결을 확인해 보자. 먼저 XML 파일의 코드다.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
tools:context=".SecondActivity">
<LinearLayout
android:id="@+id/layoutDisconnected"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<ImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@drawable/wifi_no"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="DISCONNECTED"
android:textAllCaps="true"
android:textColor="@android:color/holo_red_dark"
android:textSize="24sp"
android:textStyle="bold"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="40dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="40dp"
android:gravity="center"
android:text="인터넷에 연결되어 있지 않습니다"
android:textSize="18sp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/layoutConnected"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="gone"
android:gravity="center">
<ImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@drawable/wifi_ok"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="DISCONNECTED"
android:textAllCaps="true"
android:textColor="@android:color/holo_green_dark"
android:textSize="24sp"
android:textStyle="bold"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="40dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="40dp"
android:gravity="center"
android:text="인터넷에 연결되어 있습니다"
android:textSize="18sp"/>
</LinearLayout>
</FrameLayout>
마지막으로 위 XML 파일을 사용하는 코틀린 파일을 아래와 같이 작성한다.
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import androidx.lifecycle.Observer
import kotlinx.android.synthetic.main.activity_second.*
class SecondActivity : AppCompatActivity()
{
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
val connection = NetworkConnection(applicationContext)
connection.observe(this, Observer { isConnected ->
if (isConnected)
{
layoutDisconnected.visibility = View.GONE
layoutConnected.visibility = View.VISIBLE
} else
{
layoutConnected.visibility = View.GONE
layoutDisconnected.visibility = View.VISIBLE
}
})
}
}
여기까지 작성한 후 예제를 빌드하면 아래와 같이 작동하는 걸 볼 수 있다.
코틀린 코드의 경우 LiveData를 사용했기 때문에 코드 분석 난이도가 좀 높지만, 이걸 쓴 덕분에 실시간으로 인터넷 연결 상태를 확인해서 뒤의 이미지와 글자가 즉시 바뀌는 걸 볼 수 있다.
주의할 것은 위의 움짤처럼 마구 테스트한 다음 앱을 종료하면 에러 메시지가 나오면서 앱이 죽는 경우가 생길 수 있는데, 그것에 필요한 예외처리를 하지 않아 생기는 현상이다. 예외처리만 해주면 정상 작동한다.
'Android' 카테고리의 다른 글
[Android] 커스텀 별점(RatingBar) 사용하기 (0) | 2021.06.06 |
---|---|
[Android] All children of ConstraintLayout must have ids to use ConstraintSet 에러 해결 (0) | 2021.05.30 |
[Android] 코틀린으로 FCM 푸시 알림 보내는 법 (0) | 2021.05.23 |
[Android] ArrayList 안의 값이 [[a, b, c]] 형태일 때 처리 방법 (0) | 2021.05.10 |
[Android] editText 클릭 시 키보드가 레이아웃을 밀어올리지 않게 하는 법 (0) | 2021.05.05 |