13

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

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

4

2 回答 2

11

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

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

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

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

然后你可以像这样调用你的rest api。

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

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

于 2014-07-22T19:02:45.000 回答
4

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

我在我的服务器上使用 Grape,所以我安装了Grape-kaminarigem 来处理分页服务器端。Grape-kaminari在您的 url 上提供页面查询,并将方便的分页信息添加到标题响应中。

我写了一个小类,让我可以自动递归浏览页面,直到我使用了 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));
        }
    });
}
于 2014-07-28T20:20:23.190 回答