Coroutine/Flow
Flow 02 - in Android (with Room)
Seoplee
2022. 3. 21. 18:22
Flow in Android (with Room)
이번에는 배운 Flow를 안드로이드에서 어떤 식으로 사용할 수 있는지 알아본다.
앞서 살펴본것 처럼 Flow는 비동기 데이터 스트림이기 때문에 Data Domain에서 사용하기에도 적합하고, 여러 방법을 통해 생명주기와 결합하여 마치 LiveData를 observing하던 것 처럼 사용할 수 있다.
안드로이드에서는 내부 DB로 주로 사용되는 Room과 결합하여, 데이터가 갱신될 때 마다 매번 호출하지 않아도, 자동으로 데이터의 변화를 감지하여 ui에 뿌려주는 방법으로도 사용할 수 있다. (Room은 Rx, Flow등의 비동기 데이터 스트림을 지원한다.)
@Query("SELECT * FROM Todo")
fun getTodos(): Flow<List<Todo>>
fun getAllTodos(): Flow<List<Todo>> {
return db.TodoDao().getTodos()
}
Room이 Flow를 지원하기 때문에 리턴타입을 Flow로 지정하여 비동기 스트림으로 데이터를 관리할 수 있다.
fun getAllTodos() : Flow<List<Todo>> {
return todoRepository.getAllTodos()
}
in ViewModel
lifecycleScope.launch {
viewModel.getAllTodos().collect {
adapter.submitList(it)
}
}
in View(Activity)
위처럼 ui layer에서 Flow를 collect하여 emit되는 값들을 recyclerview adapter에 넣어줌으로, 데이터가 추가되거나 삭제돼도 별도의 호출 코드 없이 ui를 갱신할 수 있다.
그러나 위 flow는 생명주기와 연결되어 있지 않아서 collect를 하지 않아도 될 때에도 계속 수집하고 있어 리소스 낭비가 일어난다.
이 문제는 다음과 같은 방법들로 해결할 수 있다.
- asLiveData() 사용
- repeatOnLifecycle 사용
asLiveData를 사용하여, Flow를 LiveData로 변환하여 기존처럼 사용할 수 있게 해준다.
val response = todoRepository.getAllTodos().asLiveData()
혹은 repeatOnLifecycle을 이용하여 flow에 생명주기를 연결시켜주는 방법이 있다.
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED){
viewModel.getAllTodos().collect {
adapter.submitList(it)
}
}
}