From 6398f5e6811e7918f2d7c0e8c7e9a399c43a4d79 Mon Sep 17 00:00:00 2001 From: hicham Date: Sat, 30 Oct 2021 15:38:08 +0100 Subject: [PATCH] Fix the caching issue using official APIs --- .../java/com/hicham/flowlifecycle/FakeApi.kt | 26 +++++++++++++++ .../com/hicham/flowlifecycle/MainFragment.kt | 23 +++++++++++-- .../com/hicham/flowlifecycle/MainViewModel.kt | 33 +++++++++++++++---- app/src/main/res/layout/fragment_main.xml | 26 +++++++++++++-- 4 files changed, 97 insertions(+), 11 deletions(-) create mode 100644 app/src/main/java/com/hicham/flowlifecycle/FakeApi.kt diff --git a/app/src/main/java/com/hicham/flowlifecycle/FakeApi.kt b/app/src/main/java/com/hicham/flowlifecycle/FakeApi.kt new file mode 100644 index 0000000..6244007 --- /dev/null +++ b/app/src/main/java/com/hicham/flowlifecycle/FakeApi.kt @@ -0,0 +1,26 @@ +package com.hicham.flowlifecycle + +import kotlin.random.Random + +val FAKE_DATA = listOf( + "Restaurant", + "Clothing Store", + "Coffee Shop", + "Bookstore", + "Pharmacy", + "Electronics Store", + "College", + "Fast Food Restaurant", + "Cupcake Shop", + "Furniture Store", + "Supermarket", + "Gift Shop", + "Kids Store" +) + +class FakeApi { + suspend fun fetchNearbyLocations(latitude: Double, longitude: Double): List { + val size = Random.nextInt(1, FAKE_DATA.size) + return FAKE_DATA.shuffled().take(size) + } +} diff --git a/app/src/main/java/com/hicham/flowlifecycle/MainFragment.kt b/app/src/main/java/com/hicham/flowlifecycle/MainFragment.kt index 730deb4..fd7f3af 100644 --- a/app/src/main/java/com/hicham/flowlifecycle/MainFragment.kt +++ b/app/src/main/java/com/hicham/flowlifecycle/MainFragment.kt @@ -5,10 +5,12 @@ import android.content.pm.PackageManager.PERMISSION_GRANTED import android.os.Bundle import android.view.View import androidx.activity.result.contract.ActivityResultContracts +import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.lifecycle.flowWithLifecycle import androidx.lifecycle.lifecycleScope +import androidx.viewbinding.ViewBinding import com.hicham.flowlifecycle.databinding.FragmentMainBinding import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -44,8 +46,25 @@ class MainFragment : Fragment(R.layout.fragment_main) { viewLifecycleOwner.lifecycleScope.launch { viewModel.locationUpdates .flowWithLifecycle(viewLifecycleOwner.lifecycle) - .onEach { binding.location.text = "${it.latitude} ${it.longitude}" } + .launchIn(this) + viewModel.viewState + .onEach { viewState -> + binding.render(viewState) + } .launchIn(this) } } -} \ No newline at end of file + + private fun FragmentMainBinding.render(viewState: ViewState) { + progressBar.isVisible = viewState.isLoading + locationText.isVisible = !viewState.isLoading + nearbyLocations.isVisible = !viewState.isLoading + + viewState.location?.let { + locationText.text = "${it.latitude} ${it.longitude}" + } + nearbyLocations.text = viewState.nearbyLocations.joinToString(",") + } +} + + diff --git a/app/src/main/java/com/hicham/flowlifecycle/MainViewModel.kt b/app/src/main/java/com/hicham/flowlifecycle/MainViewModel.kt index d07e6ae..905e036 100644 --- a/app/src/main/java/com/hicham/flowlifecycle/MainViewModel.kt +++ b/app/src/main/java/com/hicham/flowlifecycle/MainViewModel.kt @@ -4,20 +4,38 @@ import android.annotation.SuppressLint import android.app.Application import android.location.Location import androidx.lifecycle.AndroidViewModel -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.filter -import kotlinx.coroutines.flow.flatMapLatest +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.flow.* class MainViewModel(application: Application) : AndroidViewModel(application) { private val locationObserver = LocationObserver(application) + private val api: FakeApi = FakeApi() private val hasLocationPermission = MutableStateFlow(false) - @SuppressLint("MissingPermission") val locationUpdates: Flow = hasLocationPermission .filter { it } .flatMapLatest { locationObserver.observeLocationUpdates() } + .onEach { currentLocation.emit(it) } + + private val currentLocation = MutableSharedFlow() + + val viewState: Flow = currentLocation + .mapLatest { location -> + val nearbyLocations = api.fetchNearbyLocations(location.latitude, location.longitude) + ViewState( + isLoading = false, + location = location, + nearbyLocations = nearbyLocations + ) + } + .stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(stopTimeoutMillis = 5000L), + initialValue = ViewState(isLoading = true) + ) + fun onLocationPermissionGranted() { hasLocationPermission.value = true @@ -25,6 +43,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) { } data class ViewState( - val location: Location, - val nearbyLocations: List + val isLoading: Boolean, + val location: Location? = null, + val nearbyLocations: List = emptyList() ) \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml index 313410d..4710c19 100644 --- a/app/src/main/res/layout/fragment_main.xml +++ b/app/src/main/res/layout/fragment_main.xml @@ -1,11 +1,12 @@ - + + + + \ No newline at end of file