如何在改造中处理分页

时间:2014-07-22 14:28:54

标签: android api-design retrofit okhttp

我正在使用改造来构建应用程序。一切都在游泳,但我担心我的API请求的大小,并希望使用分页将它们分开。

使用Retrofit自动翻页API的最佳策略是什么,以便默认下载所有可用数据?

2 个答案:

答案 0 :(得分:10)

首先,您需要使用您正在使用的后端服务来支持分页。其次,如果您希望通过改造从客户端获得如何实现这一点的示例,我建议您查看来自@JakeWharton的u2020项目。 GalleryService改进界面以非常简单的方式实现这种机制。这是接口本身的link

这是一个基于u2020项目的轻松示例

// See how it uses a pagination index.
public interface GalleryService {
  @GET("/gallery/{page}") //
  Gallery listGallery(@Path("page") int page);
}

通过跟踪已从其余服务下载的项目总数以及每页预定义的最大项目数,您可以计算为下一组要下载的项目调用休息服务所需的页面索引。

然后你可以这样叫你休息api。

int nextPage = totalItemsAlreadyDownloaded / ITEMS_PER_PAGE + 1;    
restApi.listGallery(nextPage);

这是一个基于u2020项目的非常简单的示例,但希望它能让您了解如何攻击它。

答案 1 :(得分:2)

所以我最终解决了我的问题:

我在服务器上使用Grape,所以我安装了Grape-kaminari gem来处理分页服务器端。 Grape-kaminari在您的网址上提供网页查询,并向标头响应添加便捷的分页信息。

我写了一个小类,允许我自动递归页面,直到我消耗了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;
        }
    }
}

然后我会在我的API调用中使用它,如下所示:

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<List<Stuff>>() {
        @Override
        public void success(final List<Stuff> 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));
        }
    });
}