Slide 27
Slide 27 text
liveData{}のKDocに書かれていることを中⼼に⾒てい
きます
(セッションでも説明がありました)
/**
* Builds a LiveData that has values yielded from the given [block] that executes on a
* [LiveDataScope].
*
* The [block] starts executing when the returned [LiveData] becomes active ([LiveData.onActive]).
* If the [LiveData] becomes inactive ([LiveData.onInactive]) while the [block] is executing, it
* will be cancelled after [timeoutInMs] milliseconds unless the [LiveData] becomes active again
* before that timeout (to gracefully handle cases like Activity rotation). Any value
* [LiveDataScope.emit]ed from a cancelled [block] will be ignored.
*
* After a cancellation, if the [LiveData] becomes active again, the [block] will be re-executed
* from the beginning. If you would like to continue the operations based on where it was stopped
* last, you can use the [LiveDataScope.initialValue] function to get the last
* [LiveDataScope.emit]ed value.
* If the [block] completes successfully *or* is cancelled due to reasons other than [LiveData]
* becoming inactive, it *will not* be re-executed even after [LiveData] goes through active
* inactive cycle.
*
* As a best practice, it is important for the [block] to cooperate in cancellation. See kotlin
* coroutines documentation for details
* https://kotlinlang.org/docs/reference/coroutines/cancellation-and-timeouts.html.
*
* ```
* // a simple LiveData that receives value 3, 3 seconds after being observed for the first time.
* val data : LiveData = liveData {
* delay(3000)
* emit(3)
* }
*
*
* // a LiveData that fetches a `User` object based on a `userId` and refreshes it every 30 seconds
* // as long as it is observed
* val userId : LiveData = ...
* val user = userId.switchMap { id ->
* liveData {
* while(true) {
* // note that `while(true)` is fine because the `delay(30_000)` below will cooperate in
* // cancellation if LiveData is not actively observed anymore
* val data = api.fetch(id) // errors are ignored for brevity
* emit(data)
* delay(30_000)
* }
* }
* }
*
* // A retrying data fetcher with doubling back-off
* val user = liveData {
* var backOffTime = 1_000
* var succeeded = false
* while(!succeeded) {
* try {
* emit(api.fetch(id))
* succeeded = true
* } catch(ioError : IOException) {
* delay(backOffTime)
* backOffTime *= minOf(backOffTime * 2, 60_000)
* }
* }
* }
*
* // a LiveData that tries to load the `User` from local cache first and then tries to fetch
* // from the server and also yields the updated value
* val user = liveData {
* // dispatch loading first
* emit(LOADING(id))
* // check local storage
* val cached = cache.loadUser(id)
* if (cached != null) {
* emit(cached)
* }
* if (cached == null || cached.isStale()) {
* val fresh = api.fetch(id) // errors are ignored for brevity
* cache.save(fresh)
* emit(fresh)
* }
* }
*
* // a LiveData that immediately receives a LiveData from the database and yields it as a
* // source but also tries to back-fill the database from the server
* val user = liveData {
* val fromDb: LiveData = roomDatabase.loadUser(id)
* emitSource(fromDb)
* val updated = api.fetch(id) // errors are ignored for brevity
* // Since we are using Room here, updating the database will update the `fromDb` LiveData
* // that was obtained above. See Room's documentation for more details.
* // https://developer.android.com/training/data-storage/room/accessing-data#query-observable
* roomDatabase.insert(updated)
* }
* ```
*
* @param context The CoroutineContext to run the given block in. Defaults to
* [EmptyCoroutineContext] combined with [Dispatchers.Main]
* @param timeoutInMs The timeout in ms before cancelling the block if there are no active observers
* ([LiveData.hasActiveObservers]. Defaults to [DEFAULT_TIMEOUT].
* @param block The block to run when the [LiveData] has active observers.
*/
@UseExperimental(ExperimentalTypeInference::class)
fun liveData(
context: CoroutineContext = EmptyCoroutineContext,
timeoutInMs: Long = DEFAULT_TIMEOUT,
@BuilderInference block: suspend LiveDataScope.() -> Unit
): LiveData = CoroutineLiveData(context, timeoutInMs, block)
•
• LiveDataがactive(onStartの後)になったときに引
数のブロックが実⾏される
• LiveDataがinactiveになったとき再度activeになら
ずに時間が経過したらブロックの処理がキャンセ
ルされる
• LiveDataのinactiveによってキャンセルされた
後、LiveDataが再度Activeになったときはブロッ
クは最初から再実⾏
• ブロックが成功したか、LiveDataがinactiveにな
る以外の理由でキャンセルになったら(Exception
がthrowされるとそうなります)、activeになって
も、もう⼀度ブロックが実⾏されることはありま
せん。
• ⻑いKDoc