Skip to content

Commit

Permalink
Fix the caching issue using official APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
hichamboushaba committed Oct 30, 2021
1 parent 0aac0d2 commit 6398f5e
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 11 deletions.
26 changes: 26 additions & 0 deletions app/src/main/java/com/hicham/flowlifecycle/FakeApi.kt
Original file line number Diff line number Diff line change
@@ -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<String> {
val size = Random.nextInt(1, FAKE_DATA.size)
return FAKE_DATA.shuffled().take(size)
}
}
23 changes: 21 additions & 2 deletions app/src/main/java/com/hicham/flowlifecycle/MainFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
}
}

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(",")
}
}


33 changes: 26 additions & 7 deletions app/src/main/java/com/hicham/flowlifecycle/MainViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,46 @@ 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<Location> = hasLocationPermission
.filter { it }
.flatMapLatest { locationObserver.observeLocationUpdates() }
.onEach { currentLocation.emit(it) }

private val currentLocation = MutableSharedFlow<Location>()

val viewState: Flow<ViewState> = 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
}
}

data class ViewState(
val location: Location,
val nearbyLocations: List<String>
val isLoading: Boolean,
val location: Location? = null,
val nearbyLocations: List<String> = emptyList()
)
26 changes: 24 additions & 2 deletions app/src/main/res/layout/fragment_main.xml
Original file line number Diff line number Diff line change
@@ -1,16 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">

<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/location"
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/location_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@id/nearby_locations"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />

<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/nearby_locations"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:textAlignment="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/location_text" />

</androidx.constraintlayout.widget.ConstraintLayout>

0 comments on commit 6398f5e

Please sign in to comment.