blob: a374d4a9c3b50ed8f935b8eb9c43fad21b0f50ea [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.paging
import androidx.lifecycle.LiveData
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.asCoroutineDispatcher
import java.util.concurrent.Executor
/**
* Builder for `LiveData<PagedList>` for Java users, given a [androidx.paging.DataSource.Factory]
* and a [androidx.paging.PagedList.Config].
*
* The required parameters are in the constructor, so you can simply construct and build, or
* optionally enable extra features (such as initial load key, or BoundaryCallback).
*
* @param Key Type of input valued used to load data from the [DataSource]. Must be integer if
* you're using [PositionalDataSource].
* @param Value Item type being presented.
*
* @see toLiveData
*/
class LivePagedListBuilder<Key : Any, Value : Any> {
private val pagedSourceFactory: PagedSourceFactory<Key, Value>
private val config: PagedList.Config
private var coroutineScope: CoroutineScope = GlobalScope
private var initialLoadKey: Key? = null
private var boundaryCallback: PagedList.BoundaryCallback<Value>? = null
private var fetchDispatcher = Dispatchers.IO
/**
* Creates a [LivePagedListBuilder] with required parameters.
*
* @param dataSourceFactory [DataSource] factory providing DataSource generations.
* @param config Paging configuration.
*/
@Deprecated("DataSource is deprecated and has been replaced by PagedSource")
constructor(dataSourceFactory: DataSource.Factory<Key, Value>, config: PagedList.Config) {
this.pagedSourceFactory = { PagedSourceWrapper(dataSourceFactory.create()) }
this.config = config
}
/**
* Creates a [LivePagedListBuilder] with required parameters.
*
* This method is a convenience for:
* ```
* LivePagedListBuilder(dataSourceFactory,
* new PagedList.Config.Builder().setPageSize(pageSize).build())
* ```
*
* @param dataSourceFactory [DataSource.Factory] providing DataSource generations.
* @param pageSize Size of pages to load.
*/
@Suppress("DEPRECATION")
@Deprecated("DataSource is deprecated and has been replaced by PagedSource")
constructor(dataSourceFactory: DataSource.Factory<Key, Value>, pageSize: Int) : this(
dataSourceFactory,
PagedList.Config.Builder().setPageSize(pageSize).build()
)
/**
* Creates a [LivePagedListBuilder] with required parameters.
*
* @param pagedSourceFactory [PagedSource] factory providing [PagedSource] generations.
*
* The returned [PagedSource] should invalidate itself if the snapshot is no longer valid. If a
* [PagedSource] becomes invalid, the only way to query more data is to create a new
* [PagedSource] by invoking the supplied [pagedSourceFactory].
*
* [pagedSourceFactory] will invoked to construct a new [PagedList] and [PagedSource] when the
* current [PagedSource] is invalidated, and pass the new [PagedList] through the
* `LiveData<PagedList>` to observers.
* @param config Paging configuration.
*/
constructor(pagedSourceFactory: PagedSourceFactory<Key, Value>, config: PagedList.Config) {
this.pagedSourceFactory = pagedSourceFactory
this.config = config
}
/**
* Creates a [LivePagedListBuilder] with required parameters.
*
* This method is a convenience for:
* ```
* LivePagedListBuilder(pagedSourceFactory,
* new PagedList.Config.Builder().setPageSize(pageSize).build())
* ```
*
* @param pagedSourceFactory [PagedSource] factory providing [PagedSource] generations.
*
* The returned [PagedSource] should invalidate itself if the snapshot is no longer valid. If a
* [PagedSource] becomes invalid, the only way to query more data is to create a new
* [PagedSource] by invoking the supplied [pagedSourceFactory].
*
* [pagedSourceFactory] will invoked to construct a new [PagedList] and [PagedSource] when the
* current [PagedSource] is invalidated, and pass the new [PagedList] through the
* `LiveData<PagedList>` to observers.
* @param pageSize Size of pages to load.
*/
constructor(pagedSourceFactory: PagedSourceFactory<Key, Value>, pageSize: Int) : this(
pagedSourceFactory,
PagedList.Config.Builder().setPageSize(pageSize).build()
)
/**
* Set the [CoroutineScope] that page loads should be launched within. The set [coroutineScope]
* allows a [PagedSource] to cancel running load operations when the results are no longer
* needed - for example, when the containing activity is destroyed.
*
* Defaults to [GlobalScope].
*
* @param coroutineScope
* @return this
*/
@Suppress("unused") // Public API
fun setCoroutineScope(coroutineScope: CoroutineScope) = this.apply {
this.coroutineScope = coroutineScope
}
/**
* First loading key passed to the first PagedList/DataSource.
*
* When a new PagedList/DataSource pair is created after the first, it acquires a load key from
* the previous generation so that data is loaded around the position already being observed.
*
* @param key Initial load key passed to the first PagedList/DataSource.
* @return this
*/
fun setInitialLoadKey(key: Key?) = this.apply {
initialLoadKey = key
}
/**
* Sets a [androidx.paging.PagedList.BoundaryCallback] on each PagedList created,
* typically used to load additional data from network when paging from local storage.
*
* Pass a [PagedList.BoundaryCallback] to listen to when the PagedList runs out of data to load.
* If this method is not called, or `null` is passed, you will not be notified when each
* [PagedSource] runs out of data to provide to its [PagedList].
*
* If you are paging from a DataSource.Factory backed by local storage, you can set a
* BoundaryCallback to know when there is no more information to page from local storage.
* This is useful to page from the network when local storage is a cache of network data.
*
* Note that when using a BoundaryCallback with a `LiveData<PagedList>`, method calls
* on the callback may be dispatched multiple times - one for each PagedList/DataSource
* pair. If loading network data from a BoundaryCallback, you should prevent multiple
* dispatches of the same method from triggering multiple simultaneous network loads.
*
* @param boundaryCallback The boundary callback for listening to PagedList load state.
* @return this
*/
fun setBoundaryCallback(boundaryCallback: PagedList.BoundaryCallback<Value>?) = this.apply {
this.boundaryCallback = boundaryCallback
}
/**
* Sets [Executor] used for background fetching of [PagedList]s, and the pages within.
*
* The library will wrap this as a [kotlinx.coroutines.CoroutineDispatcher].
*
* If not set, defaults to [Dispatchers.IO].
*
* @param fetchExecutor [Executor] for fetching data from [PagedSource]s.
* @return this
*/
fun setFetchExecutor(fetchExecutor: Executor) = this.apply {
this.fetchDispatcher = fetchExecutor.asCoroutineDispatcher()
}
/**
* Constructs the `LiveData<PagedList>`.
*
* No work (such as loading) is done immediately, the creation of the first PagedList is is
* deferred until the LiveData is observed.
*
* @return The [LiveData] of [PagedList]s
*/
fun build(): LiveData<PagedList<Value>> {
return LivePagedList(
coroutineScope,
initialLoadKey,
config,
boundaryCallback,
pagedSourceFactory,
Dispatchers.Main,
fetchDispatcher
)
}
}