Skip to content

Instantly share code, notes, and snippets.

View RBusarow's full-sized avatar
🕶️

Rick Busarow RBusarow

🕶️
View GitHub Profile
@RBusarow
RBusarow / TestCoroutineExtension.kt
Last active November 20, 2023 19:03
A JUnit 4 Rule and JUnit 5 Extension for utilizing TestCoroutineDispatcher and TestCoroutineScope from kotlinx.coroutines-test
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.test.TestCoroutineDispatcher
import kotlinx.coroutines.test.TestCoroutineScope
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.setMain
import org.junit.jupiter.api.extension.AfterAllCallback
import org.junit.jupiter.api.extension.AfterEachCallback
import org.junit.jupiter.api.extension.BeforeAllCallback
import org.junit.jupiter.api.extension.ExtendWith
import org.junit.jupiter.api.extension.ExtensionContext
@Qualifier
annotation class MainCoroutineScope
@Module
object CoroutineScopeModule {
@Provides
@MainCoroutineScope
fun provideMainCoroutineScope(): CoroutineScope = CoroutineScope(Job() + Dispatchers.Main)
@RBusarow
RBusarow / DaggerCoroutineScopeModule.kt
Created January 11, 2020 22:49
Examples of Dagger2 and Koin modules for providing dispatcher-specific CoroutineScopes.
@Module
object CoroutineScopeModule {
@Provides
fun provideDefaultCoroutineScope(): DefaultCoroutineScope = DefaultCoroutineScope()
@Provides
fun provideIOCoroutineScope(): IOCoroutineScope = IOCoroutineScope()
@Provides
@RBusarow
RBusarow / MutableLiveData2.kt
Created December 28, 2019 21:29
nullability-safe Kotlin version of MutableLiveData
@Suppress("UNCHECKED_CAST")
class MutableLiveData2<T>(value: T) : LiveData<T>(value) {
override fun getValue(): T = super.getValue() as T
public override fun setValue(value: T) = super.setValue(value)
public override fun postValue(value: T) = super.postValue(value)
}
@RBusarow
RBusarow / SharedFlow.kt
Last active February 17, 2020 05:03
Resettable lazy version of a shared Flow, which allows for multiple observers to consume a single emitter, with an automatic reset after the last consumer stops and an automatic resume when another consumer starts.
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.BroadcastChannel
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
fun <T> Flow<T>.shareIn(
scope: CoroutineScope
): Flow<T> = SharedFlow(
BroadcastManager(
class CoroutineTestRule : TestRule,
TestPolymorphicCoroutineScope by TestPolymorphicCoroutineScope() {
val dispatcher = coroutineContext[ContinuationInterceptor] as TestCoroutineDispatcher
override fun apply(
base: Statement, description: Description?
) = object : Statement() {
override fun evaluate() {
@Throws(Throwable::class)
@ExperimentalCoroutinesApi
interface TestPolymorphicCoroutineScope : TestCoroutineScope,
DefaultCoroutineScope,
IOCoroutineScope,
MainCoroutineScope,
MainImmediateCoroutineScope,
UnconfinedCoroutineScope
@ExperimentalCoroutinesApi
private class TestPolymorphicCoroutineScopeImpl(
val scope = MainCoroutineScope()
val progressIndicator = ProgressIndicator(scope)
@Module
object CoroutineScopeModule {
@Provides
fun provideMainCoroutineScope(): MainCoroutineScope = MainCoroutineScope()
}
public fun MainCoroutineScope(
job: Job = SupervisorJob()
): MainCoroutineScope = object : MainCoroutineScope {
override val coroutineContext = job + Dispatchers.Main
}
public fun MainCoroutineScope(
context: CoroutineContext
): MainCoroutineScope = object : MainCoroutineScope {
override val coroutineContext = context + Dispatchers.Main