티스토리 뷰

카테고리 없음

[Coroutine] 권장사항

ywlee 2024. 12. 16. 14:13

 

Android developer site 에서는 아래와 같이 몇가지 코루틴에 대해 권고하고 있다.

 

선요약 하자면, 

 

1. Repository 에서 coroutine dispatcher 를 하드코딩 하지 마라. 

2. suspend fun 는 기본 스레드에서 호출하기에 안전해야 함.

3. 비즈니스 및 데이터 레이어에서 코루틴 만들기

 

 

 


Repository 에서 coroutine dispatcher 를 하드코딩 하지 마라.

// OK
class NewsRepository(
    private val defaultDispatcher: CoroutineDispatcher = Dispatchers.Default
) {
    suspend fun loadNews() = withContext(defaultDispatcher) { /* ... */ }
}

// DO NOT hardcode Dispatchers
class NewsRepository {
    // DO NOT use Dispatchers.Default directly, inject it instead
    suspend fun loadNews() = withContext(Dispatchers.Default) { /* ... */ }
}

 

Testable 한 코드를 만들기 위해, dispatcher 를 하드코딩 하는것이 아닌, 

주입받아서 언제든지 TestDispathcer 로 바꿀 . 수있어야 함 .

 


suspend fun 는 기본 스레드에서 호출하기에 안전해야 함

class NewsRepository(private val ioDispatcher: CoroutineDispatcher) {

    // httpUrlConnection 은 thread 를 blocking 하기 때문에, IO 스레드로 전환해야함.
    suspend fun fetchLatestNews(): List<Article> {
        withContext(ioDispatcher) { /* ... implementation ... */ }
    }
}

.....

class GetLatestNewsWithAuthorsUseCase(
    private val newsRepository: NewsRepository,
    private val authorsRepository: AuthorsRepository
) {
    // 단순히, newsRepository 에서 fetch 하는 내용이기 때문에, 해당 useCase 에서 스레드를 전환할 필요가 없음.
    // 리스트를 생성하고 추가하는 가벼운 작업만 존재하기 때문에 Default Thread 에서도 큰 부담없음.
    suspend operator fun invoke(): List<ArticleWithAuthor> {
        val news = newsRepository.fetchLatestNews()

        val response: List<ArticleWithAuthor> = mutableEmptyList()
        for (article in news) {
            val author = authorsRepository.getAuthor(article.author)
            response.add(ArticleWithAuthor(article, author))
        }
        return Result.Success(response)
    }
}

 

이정도는 안드로이드 개발자라면 당연히 다 알만한 내용. 

 

 

 

 


비즈니스 및 데이터 레이어에서 코루틴 만들기

 

ViewModel 에서 코루틴을 만드는 것과는 별개로, Domain Layer 단에서 따로 코루틴을 만들 필요가 있는 경우. 

두가지 케이스로 나뉠것이다. 

 

1. 호출자의 scope 를 따라가는 경우 (호출자(대부분 viewModel) 가 파괴되면, 코루틴도 정지되어야 하는 경우)

 

class GetAllBooksAndAuthorsUseCase(
    private val booksRepository: BooksRepository,
    private val authorsRepository: AuthorsRepository,
) {
    suspend fun getBookAndAuthors(): BookAndAuthors {
    	// 상위 호출자의 수명주기를 따라야 하는 경우 
        return coroutineScope {
            val books = async { booksRepository.getAllBooks() }
            val authors = async { authorsRepository.getAllAuthors() }
            BookAndAuthors(books.await(), authors.await())
        }
    }
}

 

 

2. 호출자가 파괴 되더라도 작업은 끝마쳐야 하는 경우 

이 경우는 반드시 결과를 전송해야 하는 backend 작업이 있을때 사용한다.

 

예를들면, 유저가 북마크 버튼을 누르고 화면을 바로 destory 시키는 것.

화면이 파괴되면서 북마크 job 이 cancel 되면 안되기 때문에 화면과 별개로 관리.

 

class ArticlesRepository(
    private val articlesDataSource: ArticlesDataSource,
    private val externalScope: CoroutineScope,
) {
	// 이 경우는 externalScope (보통 Application 단위의 coroutine scope)을 사용.
    // join 을 사용해 작업이 완료되는 것을 기다림 
    suspend fun bookmarkArticle(article: Article) {
        externalScope.launch { articlesDataSource.bookmarkArticle(article) }
            .join()
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

참조

https://developer.android.com/kotlin/coroutines/coroutines-best-practices?hl=ko

 

Android의 코루틴 권장사항  |  Kotlin  |  Android Developers

이 페이지는 Cloud Translation API를 통해 번역되었습니다. Android의 코루틴 권장사항 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 이 페이지에서는 코루틴을

developer.android.com

 

 

 

 

 

 

 

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함