How To Handle Pagination In Retrofit
Solution 1:
First, the pagination would need to be supported by the backend service that you're using. Second if you're looking to get an example of how this can be implemented from the client side using retrofit I would recommend you take a look at the u2020 project from @JakeWharton. The GalleryService retrofit interface implements such a mechanism in a very simple manner. Here's a link to the interface itself.
Here's a light example based on the u2020 project
// See how it uses a pagination index.publicinterfaceGalleryService {
@GET("/gallery/{page}") //
Gallery listGallery(@Path("page") int page);
}
By tracking the total amount of items already downloaded from your rest service and a predefined maximum of items per page you can compute the page index necessary to call your rest service for your next set of items to download.
You can then call you rest api like this.
int nextPage = totalItemsAlreadyDownloaded / ITEMS_PER_PAGE + 1;
restApi.listGallery(nextPage);
This is a very light example based on the u2020 project but hopefully it gives you an idea of how to attack this.
Solution 2:
So I ended up solving my problem like this:
I am using Grape on my server, so I installed the Grape-kaminari
gem to handle the pagination server-side. Grape-kaminari
provides a page query on your urls, and adds handy paging information to the header response.
I wrote a small class to allow me to automatically recurse through pages until I've consumed all the data on the API:
package com.farmgeek.agricountantdemo.app.helpers;
import android.util.Log;
import retrofit.client.Header;
import retrofit.client.Response;
publicclassAPIHelper {
publicstatic PaginationData getPaginationData(Response response) {
intcurrentPage=1;
inttotalPages=1;
for (Header header : response.getHeaders()) {
try {
if (header.getName().equals("X-Page")) {
currentPage = Integer.parseInt(header.getValue());
} elseif (header.getName().equals("X-Total-Pages")) {
totalPages = Integer.parseInt(header.getValue());
}
} catch (NullPointerException e) {
// We don't care about header items// with empty names, so just skip over// them.
Log.w("APIHelper -> getPaginationData", "Skipped over header: " + e.getLocalizedMessage());
}
}
returnnewPaginationData(currentPage, totalPages);
}
publicstaticclassPaginationData {
publicfinalint page;
publicfinalint total;
publicPaginationData(int currentPage, int totalPages) {
this.page = currentPage;
this.total = totalPages;
}
}
}
I'd then use it in my API call like so:
publicvoidgetStuff(int page) {
finalRestAdapterrestAdapter= buildRestAdapter();
// Tell the sync adapter something's been added to the queueApiServiceapiService= restAdapter.create(ApiService.class);
apiService.getStuff(page, newCallback<List<Stuff>>() {
@Overridepublicvoidsuccess(final List<Stuff> stuffList, Response response) {
final APIHelper.PaginationDatapagination= APIHelper.getPaginationData(response);
for (final Stuff stuff : stuffList) {
handleRecord(stuff);
}
if (pagination.page == pagination.total) {
App.getEventBus().postSticky(newStuffSyncEvent());
App.getEventBus().post(newSuccessfulSyncEvent(Stuff.class));
} else {
// Otherwise pull down the next pagenewStuffSyncRequestAdapter().getStuff(pagination.page+1);
}
}
@Overridepublicvoidfailure(RetrofitError error) {
StringerrorMessage= error.getCause().getMessage();
App.getEventBus().post(newUnsuccessfulSyncEvent(Stuff.class, errorMessage));
}
});
}
Post a Comment for "How To Handle Pagination In Retrofit"