How to handle pagination in retrofit

后端 未结 2 1040
囚心锁ツ
囚心锁ツ 2021-02-08 14:01

I\'m building an app using retrofit. Everything\'s working swimmingly, but I\'m worried about the size of my API requests and would like to split them up using pagination.

2条回答
  •  北恋
    北恋 (楼主)
    2021-02-08 15:04

    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;
    
    public class APIHelper {
        public static PaginationData getPaginationData(Response response) {
            int currentPage = 1;
            int totalPages = 1;
            for (Header header : response.getHeaders()) {
                try {
                        if (header.getName().equals("X-Page")) {
                            currentPage = Integer.parseInt(header.getValue());
                        } else if (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());
                }
            }
            return new PaginationData(currentPage, totalPages);
        }
    
        public static class PaginationData {
            public final int page;
            public final int total;
    
            public PaginationData(int currentPage, int totalPages) {
                this.page = currentPage;
                this.total = totalPages;
            }
        }
    }
    

    I'd then use it in my API call like so:

    public void getStuff(int page) {
        final RestAdapter restAdapter = buildRestAdapter();
    
        // Tell the sync adapter something's been added to the queue
        ApiService apiService = restAdapter.create(ApiService.class);
        apiService.getStuff(page, new Callback>() {
            @Override
            public void success(final List stuffList, Response response) {
                final APIHelper.PaginationData pagination = APIHelper.getPaginationData(response);
    
                for (final Stuff stuff : stuffList) {
                    handleRecord(stuff);
                }
    
                if (pagination.page == pagination.total) {
                    App.getEventBus().postSticky(new StuffSyncEvent());
                    App.getEventBus().post(new SuccessfulSyncEvent(Stuff.class));
                } else {
                    // Otherwise pull down the next page
                    new StuffSyncRequestAdapter().getStuff(pagination.page+1);
                }
    
            }
    
            @Override
            public void failure(RetrofitError error) {
                String errorMessage = error.getCause().getMessage();
                App.getEventBus().post(new UnsuccessfulSyncEvent(Stuff.class, errorMessage));
            }
        });
    }
    

提交回复
热议问题