Retrofit 2.0的一些用法

January 25, 2016

前言

最近在项目中使用了Square家的Retrofit网络库,主要是为了配合RxJava,使用下来感觉还不错,这里稍微记录下。

我使用时最新版本是compile 'com.squareup.retrofit2:retrofit:2.0.0-beta2',按照Jake Wharton的说法虽然还是beta版但是接口已经相对稳定了,所以我们可以在项目中依赖它。由于我并没有在项目中使用过1.x版本,所以不会过多的与1.x版本比较。至于与其他网络库的对比,可自行Google,还是有很多文章的,比如stackoverflow上的这篇

初始化Retrofit实例

public static String BASE_URL = "http://example.com/";

OkHttpClient okHttpClient = new OkHttpClient();
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
okHttpClient.interceptors().add(loggingInterceptor);

Retrofit retrofit = new Retrofit.Builder().baseUrl(BASE_URL).client(okHttpClient)
                .addConverterFactory(FastJsonConvertFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();

Retrofit 2.0强制依赖okhttp,且不可替换。我们可以通过okhttp Interceptors对request和response进行一些监视或者处理,比如打印request和response,加入公用的http headers等。Interceptors是链式的,我们可以串接多个。

Converter会对request body和response body进行序列化和反序列化,它也可以添加多个,按照添加顺序,如果前面的Converter不能处理该种类型,则传递到下一个。一般我们服务端要求的请求和返回数据都是json格式,所以我们要添加一个JsonConverter进行对象的序列化和反序列化,Retrofit默认有几个写好的Converter,请参照官网。由于我在项目中采用fastjson解析json,而且需要对数据进行base64编码,所以需要自己写一个Converter。注意:json相关的Converter要放在最后,因为无法通过什么确切条件来判断一个对象是否是json对象,所以它会让所有类型的对象都通过。

CallAdapter原理跟Converter较像,默认一个请求方法会返回Call对象(可以参照源码中的DefaultCallAdapter)。我们也可以返回其他对象,比如返回RxJavaObservable对象,这时就需要添加一个自定义的CallAdapter,而Retrofit提供了对RxJava的支持。

定义请求接口

Retrofit使用特殊的注解来映射请求参数及请求方法等。

public interface Api {
	@GET
	Observable<QueryInfoResponse> queryInfo(@Url String queryInfoRequest);
	
	@GET("group/{id}/users")
  	Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
	
	@POST("login")
  	Observable<LoginResponse> login(@Body LoginRequest loginRequest);
}

关于Url的拼接,盗张图说明下吧:

url

所以建议是:

  • Base URL:总是以/结尾
  • @GET/POST等:不要以/开头

返回类型决定了使用哪一个CallAdapter

请求

Api api = retrofit.create(Api.class);
api.queryInfo("...");

下载

下载时ResponseBody返回的是一个流,相应接口如下:

public interface DownloadApi {
	@GET
	Observable<ResponseBody> downloadFile(@Url String downloadRequest);
}

downloadApi.downloadFile(url).map(new Func1<ResponseBody, File>() {
  @Override
  public File call(ResponseBody responseBody) {
      FileOutputStream outputStream = null;
      try {
          byte[] bytes = responseBody.bytes();
          File file = new File(context.getExternalFilesDir(null), "fileName");
          outputStream = new FileOutputStream(file);
          outputStream.write(bytes);
          return file;
      } catch (IOException e) {
          e.printStackTrace();
      } finally {
          if (outputStream != null) {
              try {
                  outputStream.close();
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      }
      return null;
  }
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());

上传文件

上传文件时是multipart请求,相应接口如下:

public interface UploadApi {
	@Multipart
  	@POST(Constants.ADD)
  	Observable<BlankDataResponse> add(@PartMap Map<String, RequestBody> 	params);
}

@PartMap代表由boundary分隔的每一部分,对于text/plain类型的part,可用下面的方法生成Part

Map<String, RequestBody> params = new HashMap<>();
RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain"), "token");
params.put("token", requestBody);

对于图片类型则可以如下:

File file = new File(path);
RequestBody requestBody = RequestBody.create(MediaType.parse("image/jpeg"), file);
params.put("AttachmentKey\"; filename=\"" + image.getFileName(), requestBody);

上面的代码对应于Http RequesBody内容如下:

–88fc3b38-77d8-4ec3-b057-35600d14f0b3
Content-Disposition: form-data; name=”AttachmentKey”; filename=”example.jpg”
Content-Transfer-Encoding: binary
Content-Type: image/jpeg
Content-Length: 169913

其他

  • 如果你想在Http Headers里加入公用的Header,可以如下做:
// 自定义okhttp的Interceptor
public class RequestInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request().newBuilder().addHeader("version", 				"1.0.0").build();
        return chain.proceed(request);
    }
}

// 加入链中
RequestInterceptor requestInterceptor = new RequestInterceptor();
okHttpClient.interceptors().add(requestInterceptor);
  • 取消正在进行的网络请求

对于返回类型是Call的请求,调用Call.cancel()即可。

对于返回类型是Observable的请求,调用你Subscriberunsubscribe()即可,它最终还是会去调用Call.cancel()方法。

Android DataBinding实践

Published on January 27, 2016

Gradle的一些总结

Published on June 25, 2015