Development record of developer who study hard everyday.

안드로이드 코루틴 callback flow 예제 및 사용법

안드로이드 코루틴 callback flow 예제 및 사용법

안드로이드 블로그

회사에서 프로젝트를 하면서 몇 초 단위로 DB에 직접 데이터를 호출하는 프로젝트가 있었다.

처음에는 라이브데이터로 결과값을 받아와서 UI에 나타내주었지만 고객사에서 최대한 실시간으로 데이터를 보여주길 원했다.

이럴 경우, 라이브데이터는 데이터를 관찰할 때, 데이터 흐름을 다루기 어려워서 실시간 데이터를 보여주는데 어려움이 있었다.

그래서 코루틴 flow를 적극적으로 활용해야되겠다고 생각하여 refactoring에 들어갔다.

refactoring하면서 공부한 코루틴 내용들을 정리하고자한다.

그 중에서도 오늘은 callback을 flow로 간편하게 바꿔줄 수 있는 callback flow에 대해 정리해본다.

공부할 때 참고한 자료는 아래 링크와 같다.

https://medium.com/androiddevelopers/simplifying-apis-with-coroutines-and-flow-a6fb65338765 


1. 콜백에서 나오는 데이터를 flow로 받기

@SuppressLint("MissingPermission")
fun FusedLocationProviderClient.locationFlow() = callbackFlow<Location> {
//A new Flow is crated. This code executes in a coroutine

//1. Create callback and add elements into the flow
val callback = object : LocationCallback() {
override fun onLocationResult(result: LocationResult) {
super.onLocationResult(result)

val location = result.locations.last()

try {
trySend(location)
} catch (t: Throwable) {
t.printStackTrace()
}
}
}

val locationRequest = LocationRequest.Builder(1000)
.setPriority(Priority.PRIORITY_HIGH_ACCURACY)
.build()

//2. Register the callback to get location updates by calling requestLocationUpdates
requestLocationUpdates(
locationRequest,
callback,
Looper.getMainLooper()
).addOnFailureListener { e ->
e.printStackTrace()
}

//3. Wait for the consumer to cancel the coroutine and unregister
awaitClose {
removeLocationUpdates(callback)
}
// 4. sharedFlow로 만들어주기
}.shareIn(
lifecycleScope,
replay = 1,
started = SharingStarted.WhileSubscribed()
)

1 => 콜백을 만들고 데이터를 flow에 보내준다.

2 => 콜백을 등록하고 requestLocationUpdates 호출

3 => 코루틴이 취소됐을 때 콜백을 해제한다.

4 => sharedFlow로 만들어준다.


2. flow를 collect 한다.

lifecycleScope.launch {  //1
repeatOnLifecycle(Lifecycle.State.STARTED) { //2
fusedLocationClient.locationFlow()
.collect{ currentPosition ->

Log.d(TAG, "currentLocation is $currentPosition")

if(currentLocation.value != null) {
pastLocation.value = (currentLocation.value)
}
currentLocation.value = currentPosition

val bearing = if(pastLocation.value != null && currentLocation.value != null) {
getBearing(pastLocation.value!!, currentLocation.value!!)
} else 0f

val markerOptions = MarkerOptions()
.position(LatLng(currentLocation.value!!.latitude, currentLocation.value!!.longitude))
.rotation(bearing)
.flat(true)
.icon(markerImgDescriptor)

currentMarker?.remove()
currentMarker = mMap.addMarker(markerOptions)
}
}
}

1 => flow를 collect할 때는 코루틴 영역에서 해야한다.

2 => 뷰(액티비티) 생명주기에 의해 데이터 생산 흐름이 낭비되지 않도록 repeatOnLifecycle을 활용하여 collect해준다.

참고로 나는 gps 현재 위치를 받아서 구글맵에 표시해주는 코드이다.









Share:

댓글 없음:

댓글 쓰기