Kotlin
dependencies {
implementation("it.czerwinski.android.lifecycle:lifecycle-livedata:[VERSION]")
}
Groovy
dependencies {
implementation 'it.czerwinski.android.lifecycle:lifecycle-livedata:[VERSION]'
}
LiveData that always emits a single constant value.
MediatorLiveData subclass which provides a separate LiveData per each result returned by keySelector
function
executed on subsequent values emitted by the source LiveData.
Returns a LiveData emitting a sequence of integer values, spaced by a given timeInMillis
.
val fixedIntervalLiveData: LiveData<Int> = intervalLiveData(timeInMillis = 1000L)
val varyingIntervalLiveData: LiveData<Int> = intervalLiveData { index -> (index + 1) * 1000L }
Returns a LiveData emitting only the non-null results of applying the given transform
function to each value
emitted by this LiveData.
val userOptionLiveData: LiveData<Option<User>> = // ...
val userLiveData: LiveData<User> = userOptionLiveData.mapNotNull { user -> user.getOrNull() }
Returns a LiveData emitting only values from this LiveData matching the given predicate
.
val resultLiveData: LiveData<Try<User>> = // ...
val successLiveData: LiveData<Try<User>> = resultLiveData.filter { it.isSuccess }
Returns a LiveData emitting only non-null values from this LiveData.
val userLiveData: LiveData<User?> = // ...
val nonNullUserLiveData: LiveData<User> = userLiveData.filterNotNull()
Returns a LiveData emitting only values of the given type from this LiveData.
val resultLiveData: LiveData<Try<User>> = // ...
val failureLiveData: LiveData<Failure> = resultLiveData.filterIsInstance<Failure>()
Returns a LiveData emitting accumulated value starting with the first value emitted by this LiveData and applying
operation
from left to right to current accumulator value and each value emitted by this.
val newOperationsCountLiveData: LiveData<Int?> = // ...
val operationsCountLiveData: LiveData<Int?> =
newOperationsCountLiveData.reduce { acc, next -> if (next == null) null else acc + next }
Returns a LiveData emitting non-null accumulated value starting with the first non-null value emitted by this
LiveData and applying operation
from left to right to current accumulator value and each subsequent non-null value
emitted by this LiveData.
val newOperationsCountLiveData: LiveData<Int> = // ...
val operationsCountLiveData: LiveData<Int> =
newOperationsCountLiveData.reduceNotNull { acc, next -> acc + next }
Returns a LiveData emitting values from this LiveData, after dropping values followed by newer values before
timeInMillis
expires.
val isLoadingLiveData: LiveData<Boolean> = // ...
val isLoadingThrottledLiveData: LiveData<Boolean> = isLoadingLiveData.throttleWithTimeout(
timeInMillis = 1000L,
context = viewModelScope.coroutineContext
)
Returns a LiveData emitting values from this LiveData, after dropping values followed by newer values before
timeInMillis
expires since the result LiveData has been created.
val resultLiveData: LiveData<ResultData> = // ...
val delayedResultLiveData: LiveData<ResultData> = resultLiveData.delayStart(
timeInMillis = 1000L,
context = viewModelScope.coroutineContext
)
Returns a LiveData emitting each value emitted by any of the given LiveData.
val serverError: LiveData<String> = // ...
val databaseError: LiveData<String> = // ...
val error: LiveData<String> = serverError merge databaseError
val serverError: LiveData<String> = // ...
val databaseError: LiveData<String> = // ...
val fileError: LiveData<String> = // ...
val error: LiveData<String> = merge(serverError, databaseError, fileError)
Returns a LiveData emitting pairs, triples or lists of latest values emitted by the given LiveData.
val userLiveData: LiveData<User> = // ...
val avatarUrlLiveData: LiveData<String> = // ...
val userWithAvatar: LiveData<Pair<User?, String?>> = combineLatest(userLiveData, avatarUrlLiveData)
val userLiveData: LiveData<User> = // ...
val avatarUrlLiveData: LiveData<String> = // ...
val userWithAvatar: LiveData<UserWithAvatar> =
combineLatest(userLiveData, avatarUrlLiveData) { user, avatarUrl ->
UserWithAvatar(user, avatarUrl)
}
Converts LiveData that emits other LiveData into a single LiveData that emits the items emitted by the most recently emitted LiveData.
val sourcesLiveData: LiveData<LiveData<String>> = // ...
val resultLiveData: LiveData<String?> = sourcesLiveData.switch()
Returns a GroupedLiveData
providing a set of LiveData, each emitting a different subset of values from this
LiveData, based on the result of the given keySelector
function.
val userLiveData: LiveData<User> = // ...
val userByStatusLiveData: GroupedLiveData<UserStatus, User> = errorLiveData.groupBy { user -> user.status }
val activeUserLiveData: LiveData<User> = userByStatusLiveData[UserStatus.ACTIVE]
Returns a LiveData that emits the values emitted by this LiveData or a specified default value if this LiveData has not yet emitted any values at the time of observing.
val errorLiveData: LiveData<String> = // ...
val statusLiveData: LiveData<String?> = errorLiveData.defaultIfEmpty("No errors")
Starts to listen the given source LiveData. Whenever source value is changed, it is set as a new value of this MediatorLiveData.
mediatorLiveData.addDirectSource(liveData)
is equivalent to:
mediatorLiveData.addSource(liveData) { x -> mediatorLiveData.value = x }
This package is included in both lifecycle-livedata-test-junit4
and lifecycle-livedata-test-junit5
.
Kotlin
dependencies {
testImplementation("junit:junit:4.13.1")
testImplementation("it.czerwinski.android.lifecycle:lifecycle-livedata-test-common:[VERSION]")
}
Groovy
dependencies {
testImplementation 'junit:junit:4.13.1'
testImplementation 'it.czerwinski.android.lifecycle:lifecycle-livedata-test-common:[VERSION]'
}
A callback testing values emitted by LiveData.
class MyTestClass {
@Test
fun testMethod1() {
val liveData = MutableLiveData<Int>()
val observer = liveData.test()
observer.assertNoValues()
}
@Test
fun testMethod2() {
val liveData = MutableLiveData<Int>()
val observer = liveData.test()
liveData.postValue(1)
liveData.postValue(2)
liveData.postValue(3)
observer.assertValues(1, 2, 3)
}
}
Kotlin
dependencies {
testImplementation("junit:junit:4.13.1")
testImplementation("it.czerwinski.android.lifecycle:lifecycle-livedata-test-junit4:[VERSION]")
}
Groovy
dependencies {
testImplementation 'junit:junit:4.13.1'
testImplementation 'it.czerwinski.android.lifecycle:lifecycle-livedata-test-junit4:[VERSION]'
}
JUnit4 test rule that swaps main coroutine dispatcher with UnconfinedTestDispatcher.
class MyTestClass {
@Rule
@JvmField
val testCoroutineDispatcherRule = TestCoroutineDispatcherRule()
val testCoroutineScheduler get() = testCoroutineDispatcherRule.scheduler
// ...
}
Kotlin
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.7.0")
testImplementation("it.czerwinski.android.lifecycle:lifecycle-livedata-test-junit5:[VERSION]")
}
Groovy
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
testImplementation 'it.czerwinski.android.lifecycle:lifecycle-livedata-test-junit5:[VERSION]'
}
JUnit5 extension that swaps the background executor used by the Architecture Components with a different one which executes each task synchronously.
This extension is analogous to InstantTaskExecutorRule for JUnit4.
@ExtendWith(InstantTaskExecutorExtension::class)
class MyTestClass {
// ...
}
JUnit5 extension that swaps main coroutine dispatcher with UnconfinedTestDispatcher.
Any test method parameter of type TestCoroutineScheduler will be resolved as the scheduler of the TestCoroutineDispatcher:
@ExtendWith(TestCoroutineDispatcherExtension::class)
class MyTestClass {
@Test
fun someTest(scheduler: TestCoroutineScheduler) {
// ...
scheduler.advanceTimeBy(delayTimeMillis = 1000L)
scheduler.runCurrent()
// ...
}
}
In case of parameterized tests, the scheduler can be passed as a parameter of a before method:
@ExtendWith(TestCoroutineDispatcherExtension::class)
class MyTestClass {
private lateinit var testCoroutineScheduler: TestCoroutineScheduler
@BeforeEach
fun setScheduler(scheduler: TestCoroutineScheduler) {
testCoroutineScheduler = scheduler
}
@ParameterizedTest
@MethodSource("testData")
fun someParameterizedTest(input: Int) {
// ...
}
}