如何在改造中处理分页

Joh*_*ink 10 android api-design retrofit okhttp

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

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

Mig*_*gne 10

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

这是一个基于u2020项目的简单示例

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

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

你可以这样叫你休息api.

int nextPage = totalItemsAlreadyDownloaded / ITEMS_PER_PAGE + 1;    
restApi.listGallery(nextPage);
Run Code Online (Sandbox Code Playgroud)

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


Joh*_*ink 4

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

我在我的服务器上使用 Grape,所以我安装了Grape-kaminarigem 来处理服务器端的分页。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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我会在 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));
        }
    });
}
Run Code Online (Sandbox Code Playgroud)