마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

코루틴 api 호출 await

0 추천

코루틴에서 await이라는 것이 두개이상을 돌릴때? 두개가 완료될때까지 기다렸다가 한번에 하는 거로 알고 있는데요

저의 경우에는 await을 안쓰고 이런형태로 사용합니다만 await이랑 차이점이 있을까요..? 

이런형태가 맞을지 아니면 await을 이용해야하는건지를 잘 모르겠습니다.

보시다시피 getNewBookList 2번을 호출하는데요 같은 api에 파라미터가 다르기만 하구요

하나는 다른 api 그래서 api를 3번호출하지만 일단 api 종류는 2가지입니다.

그래서 하나의 리스트에 담아 어댑터에 보내주고 어댑터에서 멀티뷰홀더로 처리해주고 있습니다

viewLifecycleOwner.lifecycleScope.launch {
    viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
        val books = mutableListOf<Books>()

        booksViewModel.getNewBookList(100).collect {
            books.addAll(it)
        }

        booksViewModel.getNewBookList(200).collect {
            books.addAll(it)
        }

        booksViewModel.getRecommendBookList().collect {
            books.addAll(it)
        }

        mainBookListAdapter.submitList(books)
    }
}

await을 써야하는게 맞을지 아니면 저렇게 쓰는게 맞을지 아니면 둘다 상관이 없는지가 궁금하네요

await을 써야된다면 그 이유, 안쓴다면 그러면 언제 써야할지..? 그런 설명을 볼 수 있는 곳이 없을까요?

수원통학러 (3,570 포인트) 님이 2022년 12월 19일 질문

1개의 답변

0 추천

Flow를 사용하고 계시네요. Flow를 여러개 사용하는데 서로 간에 의존성이 있다면 flow를 합쳐주셔야 합니다. 위처럼 하시면 flow를 collect 하긴 하는데 adapter 에 제대로 반영이 안될겁니다. 따라서

       booksViewModel.getNewBookList(100).collect {
            books.addAll(it)
            mainBookListAdapter.submitList(books)
        }

        booksViewModel.getNewBookList(200).collect {
            books.addAll(it)
            mainBookListAdapter.submitList(books)
        }

        booksViewModel.getRecommendBookList().collect {
            books.addAll(it)
            mainBookListAdapter.submitList(books)
        }
        

처럼, 데이터가 변경될 때마다 submitList를 호출해야 하지만, 이렇게 되면 비효율적이 되므로 flow에서 제공하는 zip, merge, combine 등의 오퍼레이터 중에 적합한 것을 사용하세요.

https://kt.academy/article/cc-flow-combine

그리고  combine하는 작업은 뷰모델에서 하고 그 결과만 뷰에서 처리하시면 될 것 같습니다.

combine을 사용한다면 아래처럼 합치시면 되겠죠.

val newBooksFlow1 = getNewBookList(100)
val newBooksFlow2 = getNewBookList(200)
val recommendBooksFlow = getRecommendBookList()

newBooksFlow1.combine(newBooksFlow2, recommendBooksFlow) { newBooks1, newBooks2, recommendedBooks ->
    newBooks1.plus(newBooks2).plus(recommendedBooks)
}

 

spark (224,800 포인트) 님이 2022년 12월 19일 답변
spark님이 2022년 12월 19일 수정
현재 질문에 올렸던 코드는 정상적으로 제가 원하는대로 작동을 하긴 합니다만
저렇게 제 코드를 만든이유가 3개의 api를 전부 호출하고 나서 이 3개의 데이터를
books 라는 리스트에 넣고 어댑터에 submitlist 그다음 거기서 멀티뷰홀더를 나눠서 1개의 리사이클러뷰 안에 3개의 뷰홀더로 뿌려주고 있는 형태입니다.
개인 토이 플젝이다보니 어떤게 맞는지를 잘 모르겠네요 답변주신 코드처럼 하는게 맞는지 저처럼 써도 되는지가 잘모르겠습니다
상황에 따라 현재 코드가 정상적으로 동작할 수도 있지만, 상황에 따라서는 제대로 동작하지 않을 수도 있는 코드로 보입니다. (예를들면, Flow 한곳에 delay를 몇초 넣어 보거나 데이터를 두세차례에 나누어서 emit해 보세요.)Flow를 통해 3개의 데이터를 모두 처리하고 나서 리스트를 업데이트하려면 말씀드린 오퍼레이터를 통해 데이터를 모두 합친 다음에 처리하는게 맞는 처리방법입니다.  스트림이라는 영어 단어를 찾아보시면 한쪽으로 물이 계속해서 흐르는 것을 나타낼 겁니다. 예를 들면, 네플릭스같은데서 동영상 데이터를 접속이 이루어진 후에 계속해서 내려보내는게 스트림의 대표적인 형태입니다.
Flow는 스트림 기반 API이기 때문에 여러개의 스트림으로부터 오는 데이터를 합쳐야 한다면 위에서 말씀드린 종류의 오퍼레이터를 사용하셔야 해요. 스트림을 데이터가 지속적으로 올 수 있는 리스트라고 보시면 됩니다.
그리고 API 호출을 한번만 하고 끝나는 one-shot API의 경우(대부분)는 suspend function + await를 사용해도 동시 다발적인 처리가 가능합니다.
핵심은 suspend function을 사용했을 때는 거기에 맞게, Flow를 사용했을 때는 그에 맞는 처리가 필요하다는 겁니다. Flow 문서를 정돌하시면 많은 도움이 될 겁니다.
https://kotlinlang.org/docs/flow.html
https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/
https://developer.android.com/kotlin/flow
...