This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public suspend fun ProducerScope<*>.awaitClose(block: () -> Unit = {}) { | |
... | |
try { | |
// Suspend the coroutine with a cancellable continuation | |
suspendCancellableCoroutine<Unit> { cont -> | |
// Suspend forever and resume the coroutine successfully only | |
// when the Flow/Channel is closed | |
invokeOnClose { cont.resume(Unit) } | |
} | |
} finally { |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
val FusedLocationProviderClient.locationFlow() = callbackFlow<Location> { | |
... | |
}.shareIn( | |
// Make the flow follow the applicationScope | |
applicationScope, | |
// Emit the last emitted element to new collectors | |
replay = 1, | |
// Keep the producer active while there are active subscribers | |
started = SharingStarted.WhileSubscribed() | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@ViewModelScoped // Scopes type to the ViewModel | |
class UserInputAuthData( | |
private val handle: SavedStateHandle // Default binding in ViewModelComponent | |
) { /* Cached data and logic here */ } | |
class RegistrationViewModel( | |
private val userInputAuthData: UserInputAuthData, | |
private val validateUsernameUseCase: ValidateUsernameUseCase, | |
private val validatePasswordUseCase: ValidatePasswordUseCase | |
) : ViewModel() { /* ... */ } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Module | |
@InstallIn(ViewModelComponent::class) | |
object UserAuthModule { | |
@Provides | |
fun provideValidateUsernameUseCase( | |
userInputAuthData: UserInputAuthData, // scoped to ViewModelComponent | |
repository: UserRepository | |
): ValidateUsernameUseCase { | |
return ValidateUsernameUseCaseImpl(userInputAuthData, repository) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class TransactionsRepository( | |
private val defaultDispatcher: CoroutineDispatcher = Dispatchers.Default | |
) { | |
private val transactionsCache = mutableMapOf<User, List<Transaction>() | |
private suspend fun addTransaction(user: User, transaction: Transaction) = | |
// CAREFUL! Access to the cache is not protected. | |
// Concurrency bugs can happen: threads can see stale data | |
// and race conditions may occur. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class TransactionsRepository( | |
private val defaultDispatcher: CoroutineDispatcher = Dispatchers.Default | |
) { | |
// Mutex protecting the cache mutable state | |
private val cacheMutex = Mutex() | |
private val transactionsCache = mutableMapOf<User, List<Transaction>() | |
private suspend fun addTransaction(user: User, transaction: Transaction) = | |
withContext(defaultDispatcher) { |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Implementation of a cold flow backed by a Channel that sends Location updates | |
fun FusedLocationProviderClient.locationFlow() = callbackFlow<Location> { | |
val callback = object : LocationCallback() { | |
override fun onLocationResult(result: LocationResult?) { | |
result ?: return | |
try { offer(result.lastLocation) } catch(e: Exception) {} | |
} | |
} | |
requestLocationUpdates(createLocationRequest(), callback, Looper.getMainLooper()) | |
.addOnFailureListener { e -> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class LocationActivity : AppCompatActivity() { | |
// Coroutine listening for Locations | |
private var locationUpdatesJob: Job? = null | |
override fun onStart() { | |
super.onStart() | |
locationUpdatesJob = lifecycleScope.launch { | |
locationProvider.locationFlow().collect { | |
// New location! Update the map |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class LocationActivity : AppCompatActivity() { | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
// Collects from the flow when the lifecycle is at least STARTED and | |
// STOPS the collection when it's STOPPED. | |
// It automatically restarts collecting when the lifecycle is STARTED again. | |
lifecycleOwner.addRepeatingJob(Lifecycle.State.STARTED) { | |
locationProvider.locationFlow().collect { | |
// New location! Update the map |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class LocationFragment: Fragment() { | |
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | |
// ... | |
viewLifecycleOwner.addRepeatingJob(Lifecycle.State.STARTED) { | |
locationProvider.locationFlow().collect { | |
// New location! Update the map | |
} | |
} | |
} | |
} |