본문 바로가기
프로그래밍 놀이터/안드로이드, Java

[Android] Kotlin and Flow usage

by 돼지왕 왕돼지 2022. 1. 31.
반응형

 

#
Flow 는 'emit' 으로 data 를 발행하고, 'collect' 로 data 를 받아본다.

 

#
DataStore, Retrofit, Room, WorkManager 등에서 Flow 를 지원하고 있다.

 

#
flow builder 로 flow 를 쉽게 만들 수 있으며 이 녀석은 suspend block 을 받는다.

 

#
collect 역시 suspend block 을 받는다.

 

#
final operator 가 지정되기 전까지 flow 는 emit 하지 않으며,
downstream 순서대로 로직이 수행된다.

 

#
Android UI 에서 collect 를 사용하기 위해서는 아래와 같은 방법이 사용된다.
  Flow.asLiveData():LiveData // 아래 2개를 추천함
  Lifecycle.repeatOnLifecycle(state)
  Flow.flowWithLifecycle(lifecycle, state)

 

#

lifecycleScope.launch{
	repeatOnLifecycle(Lifecycle.State.STARTED){
		viewModel.userMsgs.collect { msgs ->
			listAdapter.sumitList(msgs)
		}
	}
}

지정한 lifecycle 에 진입하면 새로운 coroutine 을 만들며 collect 를 시작하고,

해당 lifecycle 에서 벗어나면 collect 하던 coroutine 을 cancel 시킨다.

 

#
repeatOnLifecycle 은 호출한 coroutine 을 suspend 시키고, Lifecycle 이 destroy 되어야 resume 이 된다.
collect 가 suspend function 이기 때문에 여러개의 flow 를 collect 하기 위해서는 launch 를 각각 해줘야 한다.

lifecycleScope.launch{
	repeatOnLifecycle(Lifecycle.State.STARTED){
		launch{
			viewModel.userMsgs.collect{ ... }
		}
		launch{
			otherFlow.collect{ ... }
		}
	}
}

 

#

lifecycleScope.launch{
	viewModel.userMsgs
		.flowWithLifecycle(lifecycle, State.STARTED)
		.collect { msgs ->
			liadAdapter.sumitList(msgs)
		}
}

위의 repeatOnLifecycle 과 같은 기능이다.

(돼왕 : flowWithLifecycle 은 내부적으로 repeatOnLifecycle 을 사용한다. 따라서 single flow 를 collect 할 때 유용하며, multiple flow 를 collect 할 때는 repeatOnLifecycle 이 추천된다.)

 

#

lifecycleScope.launch{
	viewModel.userMsgs.collect{ msgs ->
		listAdapter.submitList(msgs)
	}
}

위 코드는 앱이 bg 상태에 가도 collect 를 계속 한다.

 

#
launchWhenX (ex. launchWhenStarted) 는 collect 는 멈추지만 emit 은 계속 진행되는 문제가 있다.

(돼왕 참고 : https://aroundck.tistory.com/7738)

 

#
StateFlow 는 buffer 역할을 하여 latest 값을 유지할 수 있다.
flow builder 로 만든 것을 collect 하면 flow block 을 처음부터 다시 태운다. 그러나 StateFlow 는 latest 값을 전달해준다.

 

#

private val _myUiState = MutableStateFlow()
val myUiState = StateFlow = _myUiState

init{
	viewModelScope.launch{
		_myUiState.value = Result.Loading
		_myUiState.value = repository.fetchStuff()
	}
}

위와 같이 설정해서 쓸 수 있다.

 

#
flow 를 StateFlow 로 변경하기 위해서는 stateIn 함수를 사용하면 좋다

val result:StateFlow<Result> = someFlow
	.stateIn(
		initialValue = Result.Loading
		scope = viewModelScope,
		started = WhileSubscribed(5000),
	)

WhileSubscribed(5000) 은 앱이 bg 상태에 들어가도 upstream flows 를 5초동안 지속시킨다.

(돼왕 : WhileSubscribe() 함수는 active observer 가 없을 때 producer 를 멈추는 함수이며, 여기에 time 인자가 들어가면 subscribe 가 안 되어도 time 시간동안 producer 를 연명시키는 것이다.)
그래서 예를 들어 screen orientation change 등에서는 보통 5초안에 앱이 다시 resume 되기 때문에 upstream 이 끊기지 않고, home button 등으로 bg 상태가 된 경우네는 5초 후에 upstream 이 끊기는 효과를 볼 수 있다.

 

 

참고 : https://youtu.be/fSB6_KE95bU

 

반응형

댓글