概述:


前文,我们比对了Volley、Retrofit、OKHttp。


抉择:AndroidHTTP请求库用Retrofit即可,有图片的加上Android-Universal-Image-Loader(或者Picasso),如果有Retrofit不能满足你的要求的话再用okhttp。一般情况下,前两个已经能很好解决大部分问题了,且用起来都比Volley简单多了。


依次学习使用Retrofit、OKHttp和GSON


Retrofit: A type-safe REST client for Android and Java


Retrofit简化了从Web API下载数据,解析成普通的Java对象(POJO)。例如,要从Github 上下载用户仓库的信息,你只需要编写下面的几行:


@GET("/users/{user}/repos")
List listRepos(@Path("user") String user);



okHttp: OKHttp是Android版Http客户端。非常高效,支持SPDY、连接池、GZIP和 HTTP 缓存。默认情况下,OKHttp会自动处理常见的网络问题,像二次连接、SSL的握手问题。 如果你的应用程序中集成了OKHttp,Retrofit默认会使用OKHttp处理其他网络层请求


Gson:GSON是将JSON解析成POJO的Java库。GSON也可以将POJO解析成JSON。

Retrofit使用GSON解析JSON数据。


使用jsonschema2pojo来创建POJO



选择源代码类型为Json,注解类型是Gson,然后点击preview.



2、通过命令行工具:jsonschema2pojo.bat -a GSON -T JSON --source jsonaddress --target java-gen



Retrofit


官网:http://square.github.io/retrofit/




android mk if ifeq 中的或 android o ify_JSON



1) POJO或模型实体类 : 从服务器获取的JSON数据将被填充到这种类的实例中。
2) 接口 : 我们需要创建一个接口来管理像GET,POST...等请求的URL,这是一个服务类。
3) RestAdapter类 : 这是一个REST客户端(RestClient)类,retrofit中默认用的是Gson来解析JSON数据,你也可以设置自己的JSON解析器,比如jackson

安装:


Maven方式:


<dependency>
  <groupId>com.squareup.retrofit</groupId>
  <artifactId>retrofit</artifactId>
  <version>1.9.0</version>
</dependency>

Gradle方式:


compile 'com.squareup.retrofit:retrofit:1.9.0'

使用


public interface GitHubService {
  @GET("/users/{user}/repos")
  List<Repo> listRepos(@Path("user") String user);
}

RestAdapter创建HTTP连接并用于创建GitHubService的实现:


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

每次调用GitHubService中的方法都会创建一个HTTP请求到服务端:


List<Repo> repos = service.listRepos("octocat");

以上使用注解描述HTTP请求的好处:


  • URL parameter replacement and query parameter support
  • Object conversion to request body (e.g., JSON, protocol buffers)
  • Multipart request body and file upload

API注解

所有请求都需要一个请求方法注解并以相对URL路径作为参数。内建了5个注解:GET, POST, PUT, DELETE, and HEAD

@GET("/users/list")


你也可以指定查询参数:


@GET("/users/list?sort=desc")


URL操作


所有请求URL可以动态改变,通过如下形式:


@GET("/group/{id}/users")
List<User> groupList(@Path("id") int groupId);

其中参数用@Path注解修饰,@Path("id")对应于{id}


还可以通过这种形式添加查询:@Query


@GET("/group/{id}/users")
List<User> groupList(@Path("id") int groupId, @Query("sort") String sort);

对于添加更复杂的查询可以采用map形式:


@GET("/group/{id}/users")
List<User> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);

REQUEST BODY请求体

@POST("/users/new")
void createUser(@Body User user, Callback<User> cb);

注意采用一个POJO作为请求体,它会被RestAdapter进行转换。同时POST方式可以传入回调。


FORM ENCODED AND MULTIPART表单域与文件上传


@FormUrlEncoded修饰表单域,每个表单域子件key-value采用@Field修饰


@FormUrlEncoded
@POST("/user/edit")
User updateUser(@Field("first_name") String first, @Field("last_name") String last);

@Multipart修饰用于文件上传,每个Part元素用@Part修饰:

@Multipart
@PUT("/user/photo")
User updateUser(@Part("photo") TypedFile photo, @Part("description") TypedString description);

处理Header:


@Headers("Cache-Control: max-age=640000")
@GET("/widget/list")
List<Widget> widgetList();
@Headers({
    "Accept: application/vnd.github.v3.full+json",
    "User-Agent: Retrofit-Sample-App"
})
@GET("/users/{username}")
User getUser(@Path("username") String username);
@GET("/user")
void getUser(@Header("Authorization") String authorization, Callback<User> callback)

如果想给所有的请求添加同一个Header,那 么可以采取RequestIntercepor形式:

RequestInterceptor requestInterceptor = new RequestInterceptor() {
  @Override
  public void intercept(RequestFacade request) {
    request.addHeader("User-Agent", "Retrofit-Sample-App");
  }
};

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

同步、异步、可观察


@GET("/user/{id}/photo")
Photo getUserPhoto(@Path("id") int id);

以下为异步的:Asynchronous execution requires the last parameter of the method be a Callback.

@GET("/user/{id}/photo")
void getUserPhoto(@Path("id") int id, Callback<Photo> cb);

但是需要注意的是在Android中,Callback是在主线程中调用执行的。

总之,带返回值形式为同步,带Callback参数形式为异步请求。


返回观察:


@GET("/user/{id}/photo")
Observable<Photo> getUserPhoto(@Path("id") int id);

Observable requests are subscribed asynchronously and observed on the same thread that executed the HTTP request. To observe on a different thread (e.g. Android's main thread) call observeOn(Scheduler) on the returned Observable.

RESPONSE OBJECT TYPE


注意:Retrofit所有的JSON与Object转换工作由RestAdapter完成


@GET("/users/list")
List<User> userList();

@GET("/users/list")
void userList(Callback<List<User>> cb);

@GET("/users/list")
Observable<List<User>> userList();

如果你想访问原始HTTP响应:

@GET("/users/list")
Response userList();

@GET("/users/list")
void userList(Callback<Response> cb);

@GET("/users/list")
Observable<Response> userList();

RestAdaper配置

JSON转换:Retrofit默认采用Gson.如果你想定制Gson转换(e.g. naming policies, date formats, custom types)可以在RestAdapter构建的时候提供一个Gson对象。

Gson gson = new GsonBuilder()
    .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
    .registerTypeAdapter(Date.class, new DateTypeAdapter())
    .create();

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

GitHubService service = restAdapter.create(GitHubService.class);

处理XML转换:

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

SoundCloudService service = restAdapter.create(SoundCloudService.class);

错误处理

class MyErrorHandler implements ErrorHandler {
  @Override public Throwable handleError(RetrofitError cause) {
    Response r = cause.getResponse();
    if (r != null && r.getStatus() == 401) {
      return new UnauthorizedException(cause);
    }
    return cause;
  }
}

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

日志处理:


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

集成okHttp


Retrofit一旦在项目中发现okHttp,会自动集成okHttp


Proguard:


-dontwarn retrofit.**
-keep class retrofit.** { *; }
-keepattributes Signature
-keepattributes Exceptions



参考:


http://stackoverflow.com/questions/27960801/should-i-use-okhttp-with-volley-library


http://stackoverflow.com/questions/16902716/comparison-of-android-networking-libraries-okhttp-retrofit-volley/


http://blog.jobbole.com/65170/


https://www.v2ex.com/t/180575


https://github.com/bboyfeiyu/android-tech-frontier/tree/master/issue-7/Retrofit%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97