Retrofit 1

ps. We adapted retrofit since 2014, 1.5.0+.

rest api 直接對應成 java interface ,且搭配 Json Mapper 直接轉換。

一個類似於 JAX-RS/JSR-311) 的實現,基於一些理由並沒有完全按照 JAX-RS 實現。

Interface:

    interface GitHub {
        @GET("/repos/{owner}/{repo}/contributors")
        Observable<List<Contributor>> contributors(
            @Path("owner") String owner,
            @Path("repo") String repo);

        @GET("/users/{user}")
        Observable<User> user(
            @Path("user") String user);

        @GET("/users/{user}/starred")
        Observable<List<Repo>> starred(
            @Path("user") String user);
    }

Usage:

        RestAdapter restAdapter = new RestAdapter.Builder()
            .setEndpoint("https://api.github.com")
            .build();

        GitHub github = restAdapter.create(GitHub.class);

        github.contributors("ReactiveX", "RxJava")
            .flatMap(list -> Observable.from(list))
            .forEach(c -> System.out.println(c.login + "\t" + c.contributions));

Models:

    static class Contributor {
        String login;
        int contributions;
    }

    static class User {
        String name;
    }

    static class Repo {
        String full_name;
    }

Retrofit 1 網路處理

retrofit 內部運作也是使用 Request 概念來運行。

Retrofit 很顯然的,希望讓開發者專注 Restful 介面,e.g. List<Repo> repos = github.repos();

處理的介面不再是網路相關的 Request ,反倒是刻意隱含了 Request ,導致網路細部操作看似無法處理,所以提供了錯誤處理註冊,Client 配置等接口。

  1. 常見的網路處理:

  2. Cache

  3. Retry
  4. Time Out
  5. Cancel
  6. Priority

使用 OkHttpClient 大多可以處理。(AOSP 4.4 之後其實也內建,不確定有沒有包進 SDK)

如果沒有用 RxJava Observable 了話,確實 Retry policy 的部份確實有點殘念,也不是無解,只是要自己辛苦點寫 ErrorHandler 重發。

使用 RxJava retry() 達到重試次數效果:

int retryLimit = 3;
Observable<Repo> repos = github.repos()
    .retry(3);

使用 RxJava retryWhen() 達到 backoff 效果:

int retryLimit = 3;
float backoff = 1.3f

Observable<Repo> repos = github.repos()
    .retryWhen(attempt -> attempt.zipWith(Observable.range(1, retryLimit), (n, i) -> i)
        .flatMap(i -> Observable.timer(i * backoff, TimeUnit.SECONDS));

Cancel 也是,如果沒有 RxJava 你只能寫 ExecutorService 處理或者操作 OkHttpClient。

使用 Rxjava unsubcribe() 取消:

Subscription reposSubscription = repos.subscribe();

reposSubscription.unsubscribe(); // 取消

其中比較困難的是 Priority ,需要處理 OkHttpClient executor 。

基本上,「RxJava + Retrofit + OkHttpClient(supports SPDY)」一起用,應該是沒什麼太大的問題。

NotRetrofit

由於 retrofit 是執行時期處理 annotations 效能有改善的空間。NotRetrofit 是改用編譯時期處理。如同 google fork square/dagger 專案的理由一樣: google/dagger2。

https://github.com/yongjhih/NotRetrofit

Retrofit 2

interface GitHub {
    @GET("/repos/{owner}/{repo}/contributors")
    Call<List<Contributor>> contributors(
        @Path("owner") String owner,
        @Path("repo") String repo);
}

解決 Retrofit 1 長久以來存在的一些問題。不直接回傳物件,而是透過一個中介 Call/Response 來包裝,使得可以保留網路資訊 Headers 。

如何取得分頁?

interface GitHub {
    // ...
    @GET
    Call<List<Contributor>> contributorsPaginate(@Url String url);
}
Call<List<Contributor>> contributorsCall = github.contributors("square", "retrofit");
Response<List<Contributor>> contributorsResponse = contributorsCall.execute();
String nextLink = contributorsResponse.headers().get("Link");
Call<List<Contributor>> contributorsNextCall = github.contributorsPaginate(nextLink);
Response<List<Contributor>> contributorsNextResponse = contributorsNextCall.execute();

Retrofit 1 分析 (1.9.0)

private class RestHandler implements InvocationHandler {
  // ...
  public Object invoke(Object proxy, Method method, final Object[] args) {
    // sync
    return invokeRequest(requestInterceptor, methodInfo, args);
    // Rx
    return rxSupport.createRequestObservable({
      (ResponseWrapper) invokeRequest(requestInterceptor, methodInfo, args);
    });
    // async
    Callback<?> callback = (Callback<?>) args[args.length - 1]; // last argument
    httpExecutor.execute({
      (ResponseWrapper) invokeRequest(interceptorTape, methodInfo, args);
    });
  }
}

See Also

results matching ""

    No results matching ""