Upgrade to Pro — share decks privately, control downloads, hide ads and more …

From LiveData to Coroutines & Flow

From LiveData to Coroutines & Flow

Talk from KUGMUC on 20.08.2020.

Recording at https://www.youtube.com/watch?v=GQ_U3LsB3s0!

Jossi Wolf

August 20, 2020
Tweet

More Decks by Jossi Wolf

Other Decks in Programming

Transcript

  1. @jossiwolf class HomeViewModel { val latestData: LiveData<String> = MutableLiveData() fun

    refresh() { val data = fetchData() latestData.post(data) } } LiveData - an example
  2. @jossiwolf class HelpViewModel( private val supermarketRepo: SupermarketRepository ): ViewModel() {

    fun fetchSupermarketOpeningHours(id: SupermarketId) = supermarketRepo.fetchOpeningHours(id).map { openingHours #-> openingHours.hours.filter { it #!= null } } } Our ViewModel
  3. @jossiwolf class HelpViewModel( private val supermarketRepo: SupermarketRepository ): ViewModel() {

    fun fetchSupermarketOpeningHours(id: SupermarketId) = supermarketRepo.fetchOpeningHours(id).map { openingHours #-> openingHours.hours.filter { it #!= null } } } Our ViewModel
  4. @jossiwolf class HelpViewModel( private val supermarketRepo: SupermarketRepository ): ViewModel() {

    fun fetchSupermarketOpeningHours(id: SupermarketId) = supermarketRepo.fetchOpeningHours(id).map { openingHours #-> openingHours.hours.filter { it #!= null } } } Our ViewModel
  5. @jossiwolf class HelpViewModel( private val supermarketRepo: SupermarketRepository ): ViewModel() {

    fun fetchSupermarketOpeningHours(id: SupermarketId) = supermarketRepo.fetchOpeningHours(id).map { openingHours #-> openingHours.hours.filter { it #!= null } } }
  6. @jossiwolf class HelpViewModel( private val supermarketRepo: SupermarketRepository ): ViewModel() {

    fun fetchSupermarketOpeningHours(id: SupermarketId) = supermarketRepo.fetchOpeningHours(id).map { openingHours #-> openingHours.hours.filter { it #!= null } } }
  7. @jossiwolf class HelpViewModel( private val supermarketRepo: SupermarketRepository ): ViewModel() {

    fun fetchSupermarketOpeningHours(id: SupermarketId) = supermarketRepo.fetchOpeningHours(id).map { openingHours #-> openingHours.hours.filter { it #!= null } } }
  8. @jossiwolf <X, Y> LiveData<Y> map( LiveData<X> source, Function<X, Y> mapFunction

    ) { MediatorLiveData<Y> result = new MediatorLiveData#<>(); result.addSource(source, (x) #-> { result.setValue(mapFunction.apply(x)); }); return result; } cs.android.com/androidx/platform/frameworks/support/+/androidx-master-dev:lifecycle/lifecycle-livedata/src/main/java/androidx/lifecycle/Transformations.java androidx.lifecycle.Transformations#map
  9. @jossiwolf <X, Y> LiveData<Y> map( LiveData<X> source, Function<X, Y> mapFunction

    ) { MediatorLiveData<Y> result = new MediatorLiveData#<>(); result.addSource(source, (x) #-> { result.setValue(mapFunction.apply(x)); }); return result; } cs.android.com/androidx/platform/frameworks/support/+/androidx-master-dev:lifecycle/lifecycle-livedata/src/main/java/androidx/lifecycle/Transformations.java androidx.lifecycle.Transformations#map
  10. @jossiwolf <X, Y> LiveData<Y> map( LiveData<X> source, Function<X, Y> mapFunction

    ) { MediatorLiveData<Y> result = new MediatorLiveData#<>(); result.addSource(source, (x) #-> { result.setValue(mapFunction.apply(x)); }); return result; } cs.android.com/androidx/platform/frameworks/support/+/androidx-master-dev:lifecycle/lifecycle-livedata/src/main/java/androidx/lifecycle/Transformations.java androidx.lifecycle.Transformations#map
  11. @jossiwolf <X, Y> LiveData<Y> map( LiveData<X> source, Function<X, Y> mapFunction

    ) { MediatorLiveData<Y> result = new MediatorLiveData#<>(); result.addSource(source, (x) #-> { result.setValue(mapFunction.apply(x)); }); return result; } cs.android.com/androidx/platform/frameworks/support/+/androidx-master-dev:lifecycle/lifecycle-livedata/src/main/java/androidx/lifecycle/Transformations.java androidx.lifecycle.Transformations#map
  12. @jossiwolf <X, Y> LiveData<Y> map( LiveData<X> source, Function<X, Y> mapFunction

    ) { MediatorLiveData<Y> result = new MediatorLiveData#<>(); result.addSource(source, (x) #-> { result.setValue(mapFunction.apply(x)); }); return result; } cs.android.com/androidx/platform/frameworks/support/+/androidx-master-dev:lifecycle/lifecycle-livedata/src/main/java/androidx/lifecycle/Transformations.java androidx.lifecycle.Transformations#map
  13. @jossiwolf fun fetchOpeningHours(id: SupermarketId): LiveData<OpenHoursInformation> { val liveData = MutableLiveData<OpenHoursInformation>()

    val openingHours = poiService.downloadOpeningHours(poiType = SUPERMARKET, id).enqueue( object: Callback<OpenHoursInformation>() { override fun onResponse(call: Call<OpenHoursInformation>, response: Response<OpenHoursInformation>) { liveData.postValue(response.body()) } ##... } ) liveData.postValue(openingHours) return liveData } Repository with LiveData + Callbacks
  14. @jossiwolf suspend fun fetchOpeningHours(id: SupermarketId): LiveData<OpenHoursInformation> { val liveData =

    MutableLiveData<OpenHoursInformation>() val openingHours = poiService.downloadOpeningHours(poiType = SUPERMARKET, id) liveData.postValue(openingHours) return liveData } Repository with LiveData + Coroutines
  15. @jossiwolf With Migration Helper suspend fun fetchOpeningHours(id: SupermarketId) = poiService.downloadOpeningHours(poiType

    = SUPERMARKET, id) @Deprecated fun fetchOpeningHoursAsLiveData(id: SupermarketId) = liveData { emit(fetchOpeningHours(id)) }
  16. @jossiwolf With Migration Helper suspend fun fetchOpeningHours(id: SupermarketId) = poiService.downloadOpeningHours(poiType

    = SUPERMARKET, id) @Deprecated fun fetchOpeningHoursAsLiveData(id: SupermarketId) = liveData { emit(fetchOpeningHours(id)) }
  17. @jossiwolf With Migration Helper suspend fun fetchOpeningHours(id: SupermarketId) = poiService.downloadOpeningHours(poiType

    = SUPERMARKET, id) @Deprecated fun fetchOpeningHoursAsLiveData(id: SupermarketId) = liveData { emit(fetchOpeningHours(id)) }
  18. @jossiwolf With Migration Helper suspend fun fetchOpeningHours(id: SupermarketId) = poiService.downloadOpeningHours(poiType

    = SUPERMARKET, id) @Deprecated fun fetchOpeningHoursAsLiveData(id: SupermarketId) = liveData { emit(fetchOpeningHours(id)) }
  19. @jossiwolf With Migration Helper suspend fun fetchOpeningHours(id: SupermarketId) = poiService.downloadOpeningHours(poiType

    = SUPERMARKET, id) @Deprecated fun fetchOpeningHoursAsLiveData(id: SupermarketId) = liveData(context = Dispatchers.IO) { emit(fetchOpeningHours(id)) }
  20. @jossiwolf class HelpViewModel( private val repo: SupermarketRepository ): ViewModel() {

    fun fetchSupermarketOpeningHours(id: SupermarketId) = repo.fetchOpeningHours(id).map { openingHours #-> openingHours.hours.filter { it #!= null } } } Our ViewModel
  21. @jossiwolf class HelpViewModel( private val repo: SupermarketRepository ): ViewModel() {

    fun fetchSupermarketOpeningHours(id: SupermarketId) = repo.fetchOpeningHoursAsLiveData(id).map { openingHours #-> openingHours.hours.filter { it #!= null } } } Our ViewModel
  22. @jossiwolf class HelpViewModel( private val repo: SupermarketRepository ): ViewModel() {

    fun fetchSupermarketOpeningHours(id: SupermarketId) = repo.fetchOpeningHoursAsLiveData(id).map { openingHours #-> openingHours.hours.filter { it #!= null } } } Our ViewModel
  23. @jossiwolf Our ViewModel class HelpViewModel( private val repo: SupermarketRepository ):

    ViewModel() { fun fetchSupermarketOpeningHours(id: SupermarketId) = repo.fetchOpeningHoursAsLiveData(id).map { openingHours #-> openingHours.hours.filter { it #!= null } } }
  24. @jossiwolf Repository with Migration Helper suspend fun fetchOpeningHours(id: SupermarketId) =

    poiService.downloadOpeningHours(poiType = SUPERMARKET, id) @Deprecated fun fetchOpeningHoursAsLiveData(id: SupermarketId) = liveData(context = Dispatchers.IO) { emit(fetchOpeningHours(id)) }
  25. @jossiwolf Our ViewModel class HelpViewModel( private val repo: SupermarketRepository ):

    ViewModel() { fun fetchSupermarketOpeningHours(id: SupermarketId) = repo.fetchOpeningHoursAsLiveData(id).map { openingHours #-> openingHours.hours.filter { it #!= null } } }
  26. @jossiwolf Our ViewModel class HelpViewModel( private val repo: SupermarketRepository ):

    ViewModel() { fun fetchSupermarketOpeningHours(id: SupermarketId) = liveData(context = Dispatchers.IO) { val openingHours = repo.fetchOpeningHours(id) val filteredHours = openingHours.hours.filter { it #!= null } emit(filteredHours) } }
  27. @jossiwolf suspend fun fetchSupermarketDetails( id: SupermarketId ): LiveData<SupermarketDetails> { val

    liveData = MutableLiveData<OpenHoursInformation>() val cachedDetails = detailsCache[id] if (cachedDetails #!= null) liveData.postValue(cachedDetails) val freshDetails = poiService.downloadDetails(SUPERMARKET, id) liveData.postValue(freshDetails) return liveData } With LiveData
  28. @jossiwolf suspend fun fetchSupermarketDetails( id: SupermarketId ): LiveData<SupermarketDetails> { val

    liveData = MutableLiveData<OpenHoursInformation>() val cachedDetails = detailsCache[id] if (cachedDetails #!= null) liveData.postValue(cachedDetails) val freshDetails = poiService.downloadDetails(SUPERMARKET, id) liveData.postValue(freshDetails) return liveData } With LiveData
  29. @jossiwolf suspend fun fetchSupermarketDetails( id: SupermarketId ): LiveData<SupermarketDetails> { val

    liveData = MutableLiveData<OpenHoursInformation>() val cachedDetails = detailsCache[id] if (cachedDetails #!= null) liveData.postValue(cachedDetails) val freshDetails = poiService.downloadDetails(SUPERMARKET, id) liveData.postValue(freshDetails) return liveData } With LiveData
  30. @jossiwolf fun fetchSupermarketDetails( id: SupermarketId ): Flow<SupermarketDetails> = flow {

    val cachedDetails = detailsCache[id] if (cachedDetails #!= null) emit(cachedDetails) val freshDetails = poiService.downloadDetails(SUPERMARKET, id) emit(freshDetails) } With Flow
  31. @jossiwolf fun fetchSupermarketDetails( id: SupermarketId ): Flow<SupermarketDetails> = flow {

    val cachedDetails = detailsCache[id] if (cachedDetails #!= null) emit(cachedDetails) val freshDetails = poiService.downloadDetails(SUPERMARKET, id) emit(freshDetails) } With Flow
  32. @jossiwolf fun fetchSupermarketDetails( id: SupermarketId ): Flow<SupermarketDetails> = flow {

    val cachedDetails = detailsCache[id] if (cachedDetails #!= null) emit(cachedDetails) val freshDetails = poiService.downloadDetails(SUPERMARKET, id) emit(freshDetails) } With Flow
  33. @jossiwolf fun fetchSupermarketDetails( id: SupermarketId ): Flow<SupermarketDetails> = flow {

    val cachedDetails = detailsCache[id] if (cachedDetails #!= null) emit(cachedDetails) val freshDetails = poiService.downloadDetails(SUPERMARKET, id) emit(freshDetails) } With Flow
  34. @jossiwolf With Flow + Migration Helper fun fetchSupermarketDetails( id: SupermarketId

    ): Flow<SupermarketDetails> = flow { … } @Deprecated("Please use Flows directly.") fun fetchSupermarketDetailsAsLiveData( id: SupermarketId ): LiveData<SupermarketDetails> = fetchSupermarketDetails(id).asLiveData()
  35. @jossiwolf With Flow + Migration Helper fun fetchSupermarketDetails( id: SupermarketId

    ): Flow<SupermarketDetails> = flow { … } @Deprecated("Please use Flows directly.") fun fetchSupermarketDetailsAsLiveData( id: SupermarketId ): LiveData<SupermarketDetails> = fetchSupermarketDetails(id).asLiveData(Dispatchers.IO)
  36. @jossiwolf With Flow + Migration Helper fun fetchSupermarketDetails( id: SupermarketId

    ): Flow<SupermarketDetails> = flow { … } @Deprecated("Please use Flows directly.") fun fetchSupermarketDetailsAsLiveData( id: SupermarketId ): LiveData<SupermarketDetails> = fetchSupermarketDetails(id).asLiveData(Dispatchers.IO)
  37. @jossiwolf With Flow + Migration Helper fun fetchSupermarketDetails( id: SupermarketId

    ): Flow<SupermarketDetails> = flow { … } @Deprecated("Please use Flows directly.") fun fetchSupermarketDetailsAsLiveData( id: SupermarketId ): LiveData<SupermarketDetails> = fetchSupermarketDetails(id).asLiveData(Dispatchers.IO)