Skip to content

Instantly share code, notes, and snippets.

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
// 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 ->
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) {
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.
@Module
@InstallIn(ViewModelComponent::class)
object UserAuthModule {
@Provides
fun provideValidateUsernameUseCase(
userInputAuthData: UserInputAuthData, // scoped to ViewModelComponent
repository: UserRepository
): ValidateUsernameUseCase {
return ValidateUsernameUseCaseImpl(userInputAuthData, repository)
@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() { /* ... */ }
@manuelvicnt
manuelvicnt / LocationRepository.kt
Last active December 28, 2022 04:17
LocationFlow shareIn
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()
)
@manuelvicnt
manuelvicnt / awaitClose.kt
Created December 9, 2020 11:42
awaitClose
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 {
@manuelvicnt
manuelvicnt / FusedLocationProviderClientUtils.kt
Created December 9, 2020 11:41
FusedLocationProviderClient.locationFlow
// Send location updates to the consumer
fun FusedLocationProviderClient.locationFlow() = callbackFlow<Location> {
// A new Flow is created. This code executes in a coroutine!
// 1. Create callback and add elements into the flow
val callback = object : LocationCallback() {
override fun onLocationResult(result: LocationResult?) {
result ?: return // Ignore null responses
for (location in result.locations) {
try {
@manuelvicnt
manuelvicnt / suspendCancellableCoroutine.kt
Created December 9, 2020 11:37
suspendCancellableCoroutine
public suspend inline fun <T> suspendCancellableCoroutine(
crossinline block: (CancellableContinuation<T>) -> Unit
): T =
// Get the Continuation object of the coroutine that it's running this suspend function
suspendCoroutineUninterceptedOrReturn { uCont ->
// Take over the control of the coroutine. The Continuation's been
// intercepted and it follows the CancellableContinuationImpl lifecycle now
val cancellable = CancellableContinuationImpl(uCont.intercepted(), ...)
/* ... */