Home > Blockchain >  Emit Article with title Kotlin Flow
Emit Article with title Kotlin Flow

Time:09-27

My task is to get whole Article with provided title from RecyclerView. When I click on specific Article i get title from it.

Room database:

  @Query("SELECT * FROM article_table WHERE title = :title")
  fun getArticleDetails(title: String): Flow<ArticleLocal>

Repository:

fun getArticleDetails(title: String): Flow<ArticleLocal> {
    return articleDao.getArticleDetails(title)
}

ViewModel:

val articleDetail = MutableStateFlow<ArticleLocal>(ArticleLocal("","","","",""))
fun getArticle(title: String) {
        viewModelScope.launch {
            articleRepository.getArticleDetails(title).collect {
                articleDetail.emit(it)
            }
        }
}

MainActivity:

lifecycleScope.launch {
     viewModel.getArticle(title)
     viewModel.articleDetail.collect {
           Log.d(TAG, "onCreate: $it")
     }
}

Problem with this code is that articleDetail on first touch gives me empty ArticleLocal e.g. title = "" I defined in ViewModel, later I get good result.

CodePudding user response:

You can get rid of additional flow to emit data and use the flow the repository directly.

ViewModel:

fun getArticle(title: String): Flow<ArticleLocal> {
    return articleRepository.getArticleDetails(title)
}

MainActivity:

lifecycleScope.launch {
    viewModel.getArticle(title).collect {
        Log.d(TAG, "onCreate: $it")
    }
}

CodePudding user response:

Use a SharedFlow so it doesn't have to publish a default result. The flow won't emit anything until it receives its first value. Use replay = 1 to get similar behavior as StateFlow as far as new subscribers getting the most recent value immediately.

You also need to consider that if the title changes, it should not keep publishing values with the old title. Currently, you have it collecting from more and more flows each time the title changes.

If you use another MutableSharedFlow just for the title, you can get it to automatically cancel unnecessary collection of those old title flows. It also allows you to get the benefit of SharingStarted.WhileSubscribed to avoid unnecessary collection from the repository when there are no subscribers.

In ViewModel:

private val articleTitle = MutableSharedFlow<String>(BufferOverflow.DROP_OLDEST)

val articleDetail = articleTitle.flatMapLatest { articleRepository.getArticleDetails(it) }
    .shareIn(viewModelScope, SharingStarted.WhileSubscribed(5000), replay = 1)

fun getArticle(title: String) {
    articleTitle.tryEmit(title)
}
  • Related