[안드로이드] java. lang. IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time. (Room Update)
흔한 이슈
위와 같은 에러를 자주 만난 적이 있을 것이다.
위 Error 를 해석하면 무엇일까?
UI 가 장시간 Lock 이 될 수 있기 때문에 기본 스레드에서 데이터베이스에 허용시킬 수 없습니다. 라는 뜻.
무슨 말일까?
UI 변경이 이루어지는 작업일 경우, UI(main) 스레드를 사용하지말라는 이야기다.
장시간 UI 가 멈추는 상황일 때, ANR이 발생해 앱이 죽을 수 있다. 따라서 다른 스레드를 이용해야 한다.
겪은 이슈
Room 을 이용하여 데이터를 저장했고,
저장한 데이터를 Update 하여 사용자 화면(UI)에 보이는 데이터가 바뀌어야 했다.
CRUD 중, Update와 Delete 하는 부분에서 위와 같은 에러가 발생하였다.
이슈가 발생한 코드는 아래와 같다.
fun updateCoupon(coupon: Coupon) {
viewModelScope.launch {
updateCouponUseCase(coupon)
)
}
이슈 해결
Room 라이브러리를 이용하여 데이터베이스를 이용할 땐,
백그라운드 스레드에서 DB 작업을 수행해야 했다.
Update와 Delete 하는 작업이 Select 와 Insert 보다 더 오래걸려 네트워크 속도가 좀 더 빠른 CoroutineScope 를 사용했다.
다만, memory leak 이 걱정되는 부분이 있어, 이 부분은 훗날 트레이드 오프가 필요한 부분일 거 같다는 생각이 든다.
Dispatchers.IO 를 이용하여 아래와 같이 코드를 작성했다.
fun updateCoupon(coupon: Coupon) {
CoroutineScope(Dispatchers.IO).launch {
updateCouponUseCase(coupon)
}
}
viewModelScope VS CoroutineScope 차이는?
viewModelScope 는 안드로이드에서 제공하는 ViewModel 을 사용할 시, 해당 스코프를 사용할 수 있다.
ViewModel 이 destroy 될 때, 자식 coroutine 들을 자동으로 취소한다.
이는 memory leak, 알지 못하는 백그라운드 작업이 지속적으로 도는 상황에서 리소스 방지를 할 수 있다.
그 이유는 Fragment 와 ViewModel 이 연결되어 있고, Fragment 와 ViewModel 이 생명주기가 같으니 해당 뷰가 지워질 때,
ViewModel 이 destroy 이 되면서 모든 job 이 cancel 된다고 생각하면 된다.
반면,
CoroutineScope 를 ViewModel 에서 사용한다면, onCleard 함수에서 scope 의 취소를 하도록 구현해야 한다.
만약 안드로이드 구성요소(Activity, Fragment, ViewModel) 의 Lifecycle 에 따라 올바로 할당 해제되지 않는다면 해제되어야 하는 Job 들이 계속해서 동작해서 메모리 릭으로 이어질 수 있다.
고로, 수동으로 onCleard 함수를 이용하여 취소하기보단, viewModelScope 를 사용하여 자동으로 취소하는게 리소스 방지에 도움된다.
귀찮음을 덜 수 있다.
viewModelScope 와 CoroutineScope(Dispachers.IO) 네트워크 속도 차이
ref. https://velog.io/@tjeong/viewModelScope-%EA%B3%84%EC%86%8D-%EC%93%B8%EA%B9%8C