Android – Paginación con Retrofit

Con Retrofit, ¿cuál es la mejor manera de cargar más datos en una respuesta REST paginada?

Fondo

Estoy migrando a Retrofit de AsyncTasks + Loaders. A diferencia de la situación de OP en esta cuestión relacionada SO , me gustaría tener Retrofit buscar datos sólo a petición en lugar de descargar todos los elementos a la vez. En la actualidad, es fácil hacer esto cuando el usuario se desplaza al final de la página de vista de lista actual invocando LoaderManager.restartLoader() .

Un ejemplo de respuesta de la API que nuestro cliente consume:

 { "data": [ { "nid": 4382, "comment_text": "some user comment", ... }, ... ], "paging": { "nextPage": "http://api.domain.net/v2/comments?page=1&pageSize=20&requestLandmark=M4ewMnwxDUsdadf0NTIwfDU2OA==%3D%3D", "itemsTotal": 5164, "page": 0, "pagerMax": 218, "requestLandmark": "M4ewMnwxDUsdadf0NTIwfDU2OA==" } } 

Sé que podemos proporcionar el parámetro 'page' a nuestro APIService como este:

 public interface APIService { @GET("/comments/{page}") // List<Comment> getComments(@Path("page") int page); } 

Sin embargo, el reto es que tenemos muchos otros puntos finales que nos proporcionan diferentes listas de datos además de comentarios (historias de usuarios, gustos, tendencias, etc.), y no nos gustaría escribir un método loadMore() para cada punto final que tenemos que buscar páginas adicionales para si hay una mejor alternativa. En otras palabras, sería torpe mantener un currentPageIndex para cada petición GET / servicio que tenemos, ya que podría desordenar el fragmento que alberga nuestras vistas de lista. La estructura de LoaderManager funcionó perfectamente para nosotros porque creamos una clase de contenedor que simplemente aceptaría la devolución de llamada de la vista de lista respectiva y, por lo tanto, teníamos un único punto para administrar la paginación independientemente del tipo de modelo de datos. Es decir, la mirada de reciclaje de nuestro Fragmento en el escucha de la Red se parecía a esto:

 @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { ... mLoadHandler.handleNewItemLoading(firstVisibleItem, visibleItemCount, totalItemCount); ... } 

y mLoaderHandler es una instancia de:

 /** * Handles new content loading for ListView if the list has been scrolled to the end */ public class ListLoadMoreHandler { private static final int MAX_PAGES_TO_LOAD = 10; private boolean mLoadingContent; private int mPageIndex = 0; private int mTotalItemCount; private final LoaderManager mLoaderManager; private final int mLoaderId; private final LoaderManager.LoaderCallbacks<?> mCallBack; public ListLoadMoreHandler(LoaderManager loaderManager, int loaderId, LoaderManager.LoaderCallbacks<?> callback) { mLoaderManager = loaderManager; mLoaderId = loaderId; mCallBack = callback; } /** * Trigger loading of new items when end of list view is reached * @param firstVisibleItem first visible item in list view * @param visibleItemCount visible items in list view * @param totalItemCount total items in list view */ public void handleNewItemLoading(int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (totalItemCount == 0 || totalItemCount < RestClient.DEFAULT_PAGINATION_SIZE) { return; } int visibleTrigger = 2; if (mPageIndex < MAX_PAGES_TO_LOAD && !mLoadingContent && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleTrigger)) { Log.d(TAG, "restarting loader"); mLoadingContent = true; mPageIndex++; mLoaderManager.restartLoader(mLoaderId, null, mCallBack); } } ... } 

¿Alguna sugerencia sobre cómo escribir una versión de ListLoadMoreHandler escalable y compatible con la adaptación?

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.