Concurrency with Kotlin Flow

Jun 5 2024 · Kotlin 1.9.20, Android 14, Android Studio Iguana

Lesson 03: Leverage Flow Operators

Combining Operators Demo

Episode complete

Play next episode

Next
Transcript

In this demo, you’ll see how to use the combine and zip operators you covered in the previous lesson.

Open CategoryViewModel.kt. You now have the knowledge to complete it. In the previous lesson, you added the functions category() and moviesForCategory().

Now, edit the initCategory() function like this:

fun initCategory(categoryId: String) {
  viewModelScope.launch {
    combine(
      category(categoryId),
      moviesForCategory(categoryId),
    ) { category, movies -> CategoryScreenViewState(category, movies) }
      .collect { _screenViewState.emit(it) }
  }
}

Add the following imports as well:

import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch

The combine operator takes both flows and merges them into a single flow. The category() function will emit faster than moviesForCategory(), but that’s OK in this case. You’ll show the category title first and movies once the flow emits them.

Next, open RatingsViewModel.kt. Make the following changes:

init {
  fetchAllMoviesWithRatings()
}

private fun fetchAllMoviesWithRatings() {
  viewModelScope.launch {
    movieRepository.fetchMoviesByCategory()
      .map { moviesByCategories -> moviesByCategories.values.flatten() }
      .zip(movieRepository.fetchMovieRatings()) { movies, ratings ->
        movies.map { movie ->
          val rating = ratings[movie.id]!!
          MovieWithRatingViewState(movie.title, rating)
        }
          .sortedByDescending { it.rating }
      }
      .collect { _movies.emit(it) }
    }
  }

Add the following imports as well:

import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.flow.zip
import kotlinx.coroutines.flow.map

The fetchAllMoviesWithRatings() uses the zip operator to merge the flow of movies with movie ratings. Since you used zip operators, both sets of data will be available at the same time.

Now, to wrap up the demo, add the following method to the MovieRepository.kt:

fun fetchMovieRatings(): Flow<Map<String, Int>> = flow {
  val movieRatings = movieService.fetchMovieRatings()
  emit(movieRatings)
}

Excellent! Run the app, and check out the new features you’ve built. You can now explore movies for a specific category and also see movie ratings.

That ends this demo. Continue with the lesson for a summary.

See forum comments
Cinema mode Download course materials from Github
Previous: Combining Operators Next: Conclusion