Implementing pagination with Retrofit in Eventyay Attendee
Pagination (Paging) is a common and powerful technique in Android Development when making HTTP requests or fetching data from the database. Eventyay Attendee has found many situations where data binding comes in as a great solution for our network calls with Retrofit. Let’s take a look at this technique. Problems without Pagination in Android DevelopmentImplementing Pagination with Kotlin with RetrofitResults and GIFConclusions PROBLEMS WITHOUT DATABINDING IN ANDROID DEVELOPMENT Making HTTP requests to fetch data from the API is a basic work in any kind of application. With the mobile application, network data usage management is an important factor that affects the loading performance of the app. Without paging, all of the data are fetched even though most of them are not displayed on the screen. Pagination is a technique to load all the data in pages of limited items, which is much more efficient IMPLEMENTING DATABINDING IN FRAGMENT VIEW Step 1: Set up dependency in build.gradle // Paging implementation "androidx.paging:paging-runtime:$paging_version" implementation "androidx.paging:paging-rxjava2:$paging_version" Step 2: Set up retrofit to fetch events from the API @GET("events?include=event-sub-topic,event-topic,event-type") fun searchEventsPaged( @Query("sort") sort: String, @Query("filter") eventName: String, @Query("page[number]") page: Int, @Query("page[size]") pageSize: Int = 5 ): Single<List<Event>> Step 3: Set up the DataSource DataSource is a base class for loading data in the paging library from Android. In Eventyay, we use PageKeyedDataSource. It will fetch the data based on the number of pages and items per page with our default parameters. With PageKeyedDataSource, three main functions loadInitial(), loadBefore(), loadAfter() are used to to load each chunks of data. class EventsDataSource( private val eventService: EventService, private val compositeDisposable: CompositeDisposable, private val query: String?, private val mutableProgress: MutableLiveData<Boolean> ) : PageKeyedDataSource<Int, Event>() { override fun loadInitial( params: LoadInitialParams<Int>, callback: LoadInitialCallback<Int, Event> ) { createObservable(1, 2, callback, null) } override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<Int, Event>) { val page = params.key createObservable(page, page + 1, null, callback) } override fun loadBefore(params: LoadParams<Int>, callback: LoadCallback<Int, Event>) { val page = params.key createObservable(page, page - 1, null, callback) } private fun createObservable( requestedPage: Int, adjacentPage: Int, initialCallback: LoadInitialCallback<Int, Event>?, callback: LoadCallback<Int, Event>? ) { compositeDisposable += eventService.getEventsByLocationPaged(query, requestedPage) .withDefaultSchedulers() .subscribe({ response -> if (response.isEmpty()) mutableProgress.value = false initialCallback?.onResult(response, null, adjacentPage) callback?.onResult(response, adjacentPage) }, { error -> Timber.e(error, "Fail on fetching page of events") } ) } } Step 4: Set up the Data Source Factory DataSourceFactory is the class responsible for creating DataSource object so that we can create PagedList (A type of List used for paging) for events. class EventsDataSourceFactory( private val compositeDisposable: CompositeDisposable, private val eventService: EventService, private val query: String?, private val mutableProgress: MutableLiveData<Boolean> ) : DataSource.Factory<Int, Event>() { override fun create(): DataSource<Int, Event> { return EventsDataSource(eventService, compositeDisposable, query, mutableProgress) } } Step 5: Adapt the current change to the ViewModel. Previously, events fetched in List<Event> Object are now should be turned into PagedList<Event>. sourceFactory = EventsDataSourceFactory( compositeDisposable, eventService, mutableSavedLocation.value, mutableProgress ) val eventPagedList = RxPagedListBuilder(sourceFactory, config) .setFetchScheduler(Schedulers.io()) .buildObservable() .cache() compositeDisposable += eventPagedList .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .distinctUntilChanged() .doOnSubscribe { mutableProgress.value = true }.subscribe({ val currentPagedEvents = mutablePagedEvents.value if…
