1 /*
<lambda>null2  * Copyright (C) 2017 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 package androidx.lifecycle
17 
18 import androidx.annotation.MainThread
19 import androidx.annotation.RestrictTo
20 import kotlin.coroutines.CoroutineContext
21 import kotlin.jvm.JvmStatic
22 import kotlinx.coroutines.CoroutineScope
23 import kotlinx.coroutines.Dispatchers
24 import kotlinx.coroutines.SupervisorJob
25 import kotlinx.coroutines.cancel
26 import kotlinx.coroutines.channels.awaitClose
27 import kotlinx.coroutines.flow.Flow
28 import kotlinx.coroutines.flow.MutableStateFlow
29 import kotlinx.coroutines.flow.StateFlow
30 import kotlinx.coroutines.flow.asStateFlow
31 import kotlinx.coroutines.flow.callbackFlow
32 import kotlinx.coroutines.flow.flowOn
33 import kotlinx.coroutines.launch
34 
35 /**
36  * Defines an object that has an Android Lifecycle. [Fragment][androidx.fragment.app.Fragment] and
37  * [FragmentActivity][androidx.fragment.app.FragmentActivity] classes implement [LifecycleOwner]
38  * interface which has the [ getLifecycle][LifecycleOwner.getLifecycle] method to access the
39  * Lifecycle. You can also implement [LifecycleOwner] in your own classes.
40  *
41  * [Event.ON_CREATE], [Event.ON_START], [Event.ON_RESUME] events in this class are dispatched
42  * **after** the [LifecycleOwner]'s related method returns. [Event.ON_PAUSE], [Event.ON_STOP],
43  * [Event.ON_DESTROY] events in this class are dispatched **before** the [LifecycleOwner]'s related
44  * method is called. For instance, [Event.ON_START] will be dispatched after
45  * [onStart][android.app.Activity.onStart] returns, [Event.ON_STOP] will be dispatched before
46  * [onStop][android.app.Activity.onStop] is called. This gives you certain guarantees on which state
47  * the owner is in.
48  *
49  * To observe lifecycle events call [.addObserver] passing an object that implements either
50  * [DefaultLifecycleObserver] or [LifecycleEventObserver].
51  */
52 public abstract class Lifecycle {
53     /**
54      * Lifecycle coroutines extensions stashes the CoroutineScope into this field.
55      *
56      * RestrictTo as it is used by lifecycle-common-ktx
57      */
58     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
59     @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
60     @set:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
61     public var internalScopeRef: AtomicReference<Any?> = AtomicReference(null)
62 
63     /**
64      * Adds a LifecycleObserver that will be notified when the LifecycleOwner changes state.
65      *
66      * The given observer will be brought to the current state of the LifecycleOwner. For example,
67      * if the LifecycleOwner is in [State.STARTED] state, the given observer will receive
68      * [Event.ON_CREATE], [Event.ON_START] events.
69      *
70      * @param observer The observer to notify.
71      */
72     @MainThread public abstract fun addObserver(observer: LifecycleObserver)
73 
74     /**
75      * Removes the given observer from the observers list.
76      *
77      * If this method is called while a state change is being dispatched,
78      * * If the given observer has not yet received that event, it will not receive it.
79      * * If the given observer has more than 1 method that observes the currently dispatched event
80      *   and at least one of them received the event, all of them will receive the event and the
81      *   removal will happen afterwards.
82      *
83      * @param observer The observer to be removed.
84      */
85     @MainThread public abstract fun removeObserver(observer: LifecycleObserver)
86 
87     /**
88      * Returns the current state of the Lifecycle.
89      *
90      * @return The current state of the Lifecycle.
91      */
92     @get:MainThread public abstract val currentState: State
93 
94     /**
95      * Returns a [StateFlow] where the [StateFlow.value] represents the current [State] of this
96      * Lifecycle.
97      *
98      * @return [StateFlow] where the [StateFlow.value] represents the current [State] of this
99      *   Lifecycle.
100      */
101     public open val currentStateFlow: StateFlow<Lifecycle.State>
102         get() {
103             val mutableStateFlow = MutableStateFlow(currentState)
104             LifecycleEventObserver { _, event -> mutableStateFlow.value = event.targetState }
105                 .also { addObserver(it) }
106             return mutableStateFlow.asStateFlow()
107         }
108 
109     public enum class Event {
110         /** Constant for onCreate event of the [LifecycleOwner]. */
111         ON_CREATE,
112 
113         /** Constant for onStart event of the [LifecycleOwner]. */
114         ON_START,
115 
116         /** Constant for onResume event of the [LifecycleOwner]. */
117         ON_RESUME,
118 
119         /** Constant for onPause event of the [LifecycleOwner]. */
120         ON_PAUSE,
121 
122         /** Constant for onStop event of the [LifecycleOwner]. */
123         ON_STOP,
124 
125         /** Constant for onDestroy event of the [LifecycleOwner]. */
126         ON_DESTROY,
127 
128         /** An [Event] constant that can be used to match all events. */
129         ON_ANY;
130 
131         /**
132          * Returns the new [Lifecycle.State] of a [Lifecycle] that just reported this
133          * [Lifecycle.Event].
134          *
135          * Throws [IllegalArgumentException] if called on [.ON_ANY], as it is a special value used
136          * by [OnLifecycleEvent] and not a real lifecycle event.
137          *
138          * @return the state that will result from this event
139          */
140         public val targetState: State
141             get() {
142                 when (this) {
143                     ON_CREATE,
144                     ON_STOP -> return State.CREATED
145                     ON_START,
146                     ON_PAUSE -> return State.STARTED
147                     ON_RESUME -> return State.RESUMED
148                     ON_DESTROY -> return State.DESTROYED
149                     ON_ANY -> {}
150                 }
151                 throw IllegalArgumentException("$this has no target state")
152             }
153 
154         public companion object {
155             /**
156              * Returns the [Lifecycle.Event] that will be reported by a [Lifecycle] leaving the
157              * specified [Lifecycle.State] to a lower state, or `null` if there is no valid event
158              * that can move down from the given state.
159              *
160              * @param state the higher state that the returned event will transition down from
161              * @return the event moving down the lifecycle phases from state
162              */
163             @JvmStatic
164             public fun downFrom(state: State): Event? {
165                 return when (state) {
166                     State.CREATED -> ON_DESTROY
167                     State.STARTED -> ON_STOP
168                     State.RESUMED -> ON_PAUSE
169                     else -> null
170                 }
171             }
172 
173             /**
174              * Returns the [Lifecycle.Event] that will be reported by a [Lifecycle] entering the
175              * specified [Lifecycle.State] from a higher state, or `null` if there is no valid event
176              * that can move down to the given state.
177              *
178              * @param state the lower state that the returned event will transition down to
179              * @return the event moving down the lifecycle phases to state
180              */
181             @JvmStatic
182             public fun downTo(state: State): Event? {
183                 return when (state) {
184                     State.DESTROYED -> ON_DESTROY
185                     State.CREATED -> ON_STOP
186                     State.STARTED -> ON_PAUSE
187                     else -> null
188                 }
189             }
190 
191             /**
192              * Returns the [Lifecycle.Event] that will be reported by a [Lifecycle] leaving the
193              * specified [Lifecycle.State] to a higher state, or `null` if there is no valid event
194              * that can move up from the given state.
195              *
196              * @param state the lower state that the returned event will transition up from
197              * @return the event moving up the lifecycle phases from state
198              */
199             @JvmStatic
200             public fun upFrom(state: State): Event? {
201                 return when (state) {
202                     State.INITIALIZED -> ON_CREATE
203                     State.CREATED -> ON_START
204                     State.STARTED -> ON_RESUME
205                     else -> null
206                 }
207             }
208 
209             /**
210              * Returns the [Lifecycle.Event] that will be reported by a [Lifecycle] entering the
211              * specified [Lifecycle.State] from a lower state, or `null` if there is no valid event
212              * that can move up to the given state.
213              *
214              * @param state the higher state that the returned event will transition up to
215              * @return the event moving up the lifecycle phases to state
216              */
217             @JvmStatic
218             public fun upTo(state: State): Event? {
219                 return when (state) {
220                     State.CREATED -> ON_CREATE
221                     State.STARTED -> ON_START
222                     State.RESUMED -> ON_RESUME
223                     else -> null
224                 }
225             }
226         }
227     }
228 
229     /**
230      * Lifecycle states. You can consider the states as the nodes in a graph and [Event]s as the
231      * edges between these nodes.
232      */
233     public enum class State {
234         /**
235          * Destroyed state for a LifecycleOwner. After this event, this Lifecycle will not dispatch
236          * any more events. For instance, for an [android.app.Activity], this state is reached
237          * **right before** Activity's [onDestroy][android.app.Activity.onDestroy] call.
238          */
239         DESTROYED,
240 
241         /**
242          * Initialized state for a LifecycleOwner. For an [android.app.Activity], this is the state
243          * when it is constructed but has not received [onCreate][android.app.Activity.onCreate]
244          * yet.
245          */
246         INITIALIZED,
247 
248         /**
249          * Created state for a LifecycleOwner. For an [android.app.Activity], this state is reached
250          * in two cases:
251          * * after [onCreate][android.app.Activity.onCreate] call;
252          * * **right before** [onStop][android.app.Activity.onStop] call.
253          */
254         CREATED,
255 
256         /**
257          * Started state for a LifecycleOwner. For an [android.app.Activity], this state is reached
258          * in two cases:
259          * * after [onStart][android.app.Activity.onStart] call;
260          * * **right before** [onPause][android.app.Activity.onPause] call.
261          */
262         STARTED,
263 
264         /**
265          * Resumed state for a LifecycleOwner. For an [android.app.Activity], this state is reached
266          * after [onResume][android.app.Activity.onResume] is called.
267          */
268         RESUMED;
269 
270         /**
271          * Compares if this State is greater or equal to the given `state`.
272          *
273          * @param state State to compare with
274          * @return true if this State is greater or equal to the given `state`
275          */
276         public fun isAtLeast(state: State): Boolean {
277             return compareTo(state) >= 0
278         }
279     }
280 }
281 
282 /** An object reference that may be updated atomically. */
283 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
284 public expect class AtomicReference<V>
285 /** Creates a new [AtomicReference] with the given [initialValue]. */
286 public constructor(initialValue: V) {
287 
288     /** Returns the current value. */
getnull289     public fun get(): V
290 
291     /** Atomically sets the value to [newValue] if the current value is equal to [expectedValue]. */
292     public fun compareAndSet(expectedValue: V, newValue: V): Boolean
293 }
294 
295 /**
296  * [CoroutineScope] tied to this [Lifecycle].
297  *
298  * This scope will be cancelled when the [Lifecycle] is destroyed.
299  *
300  * This scope is bound to
301  * [Dispatchers.Main.immediate][kotlinx.coroutines.MainCoroutineDispatcher.immediate]
302  */
303 public val Lifecycle.coroutineScope: LifecycleCoroutineScope
304     get() {
305         while (true) {
306             val existing = internalScopeRef.get() as LifecycleCoroutineScopeImpl?
307             if (existing != null) {
308                 return existing
309             }
310             val newScope =
311                 LifecycleCoroutineScopeImpl(this, SupervisorJob() + Dispatchers.Main.immediate)
312             if (internalScopeRef.compareAndSet(null, newScope)) {
313                 newScope.register()
314                 return newScope
315             }
316         }
317     }
318 
319 /**
320  * [CoroutineScope] tied to a [Lifecycle] and
321  * [Dispatchers.Main.immediate][kotlinx.coroutines.MainCoroutineDispatcher.immediate]
322  *
323  * This scope will be cancelled when the [Lifecycle] is destroyed.
324  */
325 public expect abstract class LifecycleCoroutineScope internal constructor() : CoroutineScope {
326     internal abstract val lifecycle: Lifecycle
327 }
328 
329 internal class LifecycleCoroutineScopeImpl(
330     override val lifecycle: Lifecycle,
331     override val coroutineContext: CoroutineContext
332 ) : LifecycleCoroutineScope(), LifecycleEventObserver {
333     init {
334         // in case we are initialized on a non-main thread, make a best effort check before
335         // we return the scope. This is not sync but if developer is launching on a non-main
336         // dispatcher, they cannot be 100% sure anyways.
337         if (lifecycle.currentState == Lifecycle.State.DESTROYED) {
338             coroutineContext.cancel()
339         }
340     }
341 
registernull342     fun register() {
343         launch(Dispatchers.Main.immediate) {
344             if (lifecycle.currentState >= Lifecycle.State.INITIALIZED) {
345                 lifecycle.addObserver(this@LifecycleCoroutineScopeImpl)
346             } else {
347                 coroutineContext.cancel()
348             }
349         }
350     }
351 
onStateChangednull352     override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
353         if (lifecycle.currentState <= Lifecycle.State.DESTROYED) {
354             lifecycle.removeObserver(this)
355             coroutineContext.cancel()
356         }
357     }
358 }
359 
360 /** Creates a [Flow] of [Lifecycle.Event]s containing values dispatched by this [Lifecycle]. */
361 public val Lifecycle.eventFlow: Flow<Lifecycle.Event>
362     get() =
<lambda>null363         callbackFlow {
364                 val observer = LifecycleEventObserver { _, event ->
365                     trySend(event)
366 
367                     // Completes the producer if lifecycle is `DESTROYED`.
368                     if (event == Lifecycle.Event.ON_DESTROY) {
369                         close()
370                     }
371                 }
372                 addObserver(observer)
373                 awaitClose { removeObserver(observer) }
374             }
375             .flowOn(Dispatchers.Main.immediate)
376