Skip to content

Instantly share code, notes, and snippets.

@jerryOkafor
Last active July 17, 2018 12:53
Show Gist options
  • Save jerryOkafor/187c5a7892b2ea6875b0e48477d8218d to your computer and use it in GitHub Desktop.
Save jerryOkafor/187c5a7892b2ea6875b0e48477d8218d to your computer and use it in GitHub Desktop.
/**
* Data class that is necessary for a UI to show a listing and interact w/ the rest of the system
*/
data class Listing<T>(
// the LiveData of paged lists for the UI to observe
val pagedList: LiveData<PagedList<T>>,
// represents the network request status to show to the user
val networkState: LiveData<NetworkState>,
// represents the refresh status to show to the user. Separate from networkState, this
// value is importantly only when refresh is requested.
val refreshState: LiveData<NetworkState>,
// refreshes the whole data and fetches it from scratch.
val refresh: () -> Unit,
// retries any failed requests.
val retry: () -> Unit)
class DataSource(
private val apiService: ApiService,
private val retryExecutor: Executor,
//You can pass all other extra params that you need here.
) : PageKeyedDataSource<Int, Deliverable>() {
// keep a function reference for the retry event
private var retry: (() -> Any)? = null
/**
* There is no sync on the state because paging will always call loadInitial first then wait
* for it to return some success value before calling loadAfter.
*/
val networkState = MutableLiveData<NetworkState>()
val initialLoad = SingleLiveEvent<NetworkState>()
fun retryAllFailed() {
val prevRetry = retry
retry = null
prevRetry?.let {
retryExecutor.execute {
it.invoke()
}
}
}
override fun loadInitial(params: LoadInitialParams<Int>, callback: LoadInitialCallback<Int, Deliverable>) {
Timber.d("Loading initial value")
}
override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<Int, Deliverable>) {
Timber.d("Load after called. Offset: ${params.key}, Page size: ${params.requestedLoadSize}")
}
override fun loadBefore(params: LoadParams<Int>, callback: LoadCallback<Int, Deliverable>) {
Timber.d("Load before called")
//This is never used
}
}
class DataSourceFactory(
private val apiservice: ApiService,
private val retryExecutor: Executor,
//You can pass all other extra params that you need here.
) : DataSource.Factory<Int, Deliverable>() {
val sourceLiveData = MutableLiveData<DataSource>()
override fun create(): DataSource<Int, Deliverable> {
val source = DataSource(//Pass all required params here.)
sourceLiveData.postValue(source)
return source
}
}
//Then on the repository or any other place you are creating your data source
fun history(//Pass params here): Listing<Deliverable> {
val sourceFactory = DataSourceFactory(//Pass params)
val config = PagedList.Config.Builder()
.setPageSize(10)
.build()
val livePageList = LivePagedListBuilder(sourceFactory, config)
.build()
val refreshState = Transformations.switchMap(sourceFactory.sourceLiveData) {
it.initialLoad
}
return Listing(
pagedList = livePageList,
networkState = Transformations.switchMap(sourceFactory.sourceLiveData) {
it.networkState
},
retry = { sourceFactory.sourceLiveData.value?.retryAllFailed() },
refresh = { sourceFactory.sourceLiveData.value?.invalidate() },
refreshState = refreshState
)
}
//The in viewModel, observe network state and trigger retries as follows
private val repoResult = //create repo list from rrepository
private val transports = Transformations.switchMap(repoResult) { it.pagedList }!!
private val networkState = Transformations.switchMap(repoResult) { it.networkState }!!
private val refreshState = Transformations.switchMap(repoResult) { it.refreshState }!!
//call refresh and retry as follows
fun refresh() {
repoResult.value?.refresh?.invoke()
}
fun retry() {
val listing = repoResult?.value
listing?.retry?.invoke()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment