1 /* 2 * Copyright 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.lifecycle.testing 18 19 import androidx.lifecycle.Lifecycle 20 import androidx.lifecycle.LifecycleOwner 21 import androidx.lifecycle.LifecycleRegistry 22 import kotlin.jvm.JvmOverloads 23 import kotlinx.coroutines.CoroutineDispatcher 24 import kotlinx.coroutines.Dispatchers 25 import kotlinx.coroutines.runBlocking 26 import kotlinx.coroutines.withContext 27 28 /** 29 * Create a [LifecycleOwner] that allows changing the state via the [handleLifecycleEvent] method or 30 * [currentState] property. 31 * 32 * Under the hood, this uses a [LifecycleRegistry]. However, it uses 33 * [Dispatchers.Main.immediate][kotlinx.coroutines.MainCoroutineDispatcher.immediate] as the default 34 * [coroutineDispatcher] to ensure that all mutations to the [current state][currentState] are run 35 * on that dispatcher, no matter what thread you mutate the state from. 36 * 37 * @param initialState The initial [Lifecycle.State]. 38 * @param coroutineDispatcher A [CoroutineDispatcher] to use when dispatching work from this class. 39 */ 40 public class TestLifecycleOwner 41 @JvmOverloads 42 constructor( 43 initialState: Lifecycle.State = Lifecycle.State.STARTED, 44 private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.Main.immediate 45 ) : LifecycleOwner { 46 // it is in test artifact 47 private val lifecycleRegistry = <lambda>null48 LifecycleRegistry.createUnsafe(this).apply { currentState = initialState } 49 50 override val lifecycle: LifecycleRegistry 51 get() = lifecycleRegistry 52 53 /** 54 * Update the [currentState] by moving it to the state directly after the given [event]. This is 55 * safe to mutate on any thread, but will block that thread during execution. 56 */ handleLifecycleEventnull57 public fun handleLifecycleEvent(event: Lifecycle.Event) { 58 runBlocking(coroutineDispatcher) { lifecycleRegistry.handleLifecycleEvent(event) } 59 } 60 61 /** 62 * The current [Lifecycle.State] of this owner. This is safe to call on any thread but is 63 * thread-blocking and should not be called from within a coroutine (use [setCurrentState] 64 * instead). 65 */ 66 public var currentState: Lifecycle.State <lambda>null67 get() = runBlocking(coroutineDispatcher) { lifecycleRegistry.currentState } 68 set(value) { <lambda>null69 runBlocking(coroutineDispatcher) { lifecycleRegistry.currentState = value } 70 } 71 72 /** 73 * Updates the [currentState]. This suspending function is safe to call on any thread and will 74 * not block that thread. If the state should be updated from outside of a suspending function, 75 * use [currentState] property syntax instead. 76 */ setCurrentStatenull77 public suspend fun setCurrentState(state: Lifecycle.State) { 78 withContext(coroutineDispatcher) { lifecycleRegistry.currentState = state } 79 } 80 81 /** Get the number of observers. */ 82 public val observerCount: Int 83 get() = lifecycleRegistry.observerCount 84 } 85