Retrofit的使用教程(三)

RequestInterceptor 请求拦截器

对于网络访问请求的重复操作部分都可以这么做. 拦截器的执行是在执行网络访问前最后执行的. 所以会覆盖前面的某些配置.
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();

 

 ERROR
 如果需要自定义一个网络访问错误的处理方法,需要自定义一个ErrorHandler.下面的代码当返回码是401的时候抛出一个自定义异常.
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;     //返回值不能是null,否则运行时会出现异常.
  }
}
RestAdapter restAdapter = new RestAdapter.Builder()
    .setEndpoint("https://api.github.com")
    .setErrorHandler(new MyErrorHandler())
    .build();
特别注意在网络访问时返回码为40x,50x,IOException时,都会转化为RetrofitError再次抛出.
因为RetrofitError是RuntimeException.不会提示用户进行捕捉.所以如果在Android平台上就会造成应用崩溃.
解决办法就是不要采用同步的方式,采用CallBack异步的方式. 异常在CallBack的failure()方法中就可以得到妥善的处理.不会再次抛出.
 
ErrorHandler的handlerError()方法不能retrun null.否则会抛出RuntimeException.
 
实际开发中对Error最好做不同的处理.通过RetrofitError.getKind()获得具体的错误类型.
public enum Kind {  
         /** An {@link IOException} occurred while communicating to the server. */
         NETWORK,(连接错误)
         /** An exception was thrown while (de)serializing a body. */
         CONVERSION,(转换错误)
         /** A non-200 HTTP status code was received from the server. */
         HTTP,(非200错误, 如返回码为40x 50x)
         /**
          * An internal error occurred while attempting to execute a 
          request. It is best practice to re-throw this exception so your application crashes.
          */
         UNEXPECTED
     }

可以根据RetrofitError.getKind()来获取具体是哪种类型的错误.

 

Client.

retrofit在android平台下默认进行了网络访问的client选择.

当有okhttp的时候使用Okhttp进行网络访问(一般需要okhttp2.0以上的版本).

当没有没有OkhttpClient的时候会判断Android的版本,如果sdk版本<2.3,就使用Httpclient.而sdk版本大于等于2.3,就使用UrlConnection.

如果想使用特定的框架,可以通过new RestAdaper.Builder().setClient()来指定使用特定的client.

retrofit默认实现了几个Client.包括OkClient(okhttp).  ApacheClient(httpClient). UrlConnectionClient(urlConnection).

 

 

LOGGING
可以通过添加logging level等级来详细观看请求和响应. logging level 分为 BASIC, FULL, HEADERS, and NONE.
 Full等级将会打印request和response的headers.body,和metadata等
RestAdapter restAdapter = new RestAdapter.Builder()
    .setLogLevel(RestAdapter.LogLevel.FULL)
    .setEndpoint("https://api.github.com")
    .build();

不同于拦截器或者ErrorHandler,可以在RestAdapter生命周期的任何时候通过setLogLevel()添加或者更改logging level.

  

JacksonConverter 
如果想使用Jackson,而不使用Gson 可以自定义如下的Converter.
public class JacksonConverter implements Converter {
  private static final String MIME_TYPE = "application/json; charset=UTF-8";

  private final ObjectMapper objectMapper;

  public JacksonConverter() {
    this(new ObjectMapper());
  }

  public JacksonConverter(ObjectMapper objectMapper) {
    this.objectMapper = objectMapper;
  }

  @Override public Object fromBody(TypedInput body, Type type) throws ConversionException {
    try {
      JavaType javaType = objectMapper.getTypeFactory().constructType(type);
      return objectMapper.readValue(body.in(), javaType);
    } catch (JsonParseException e) {
      throw new ConversionException(e);
    } catch (JsonMappingException e) {
      throw new ConversionException(e);
    } catch (IOException e) {
      throw new ConversionException(e);
    }
  }

  @Override public TypedOutput toBody(Object object) {
    try {
      String json = objectMapper.writeValueAsString(object);
      return new TypedByteArray(MIME_TYPE, json.getBytes("UTF-8"));
    } catch (JsonProcessingException e) {
      throw new AssertionError(e);
    } catch (UnsupportedEncodingException e) {
      throw new AssertionError(e);
    }
  }
}

 

 写在最后.
Retrofit对Android平台的支持还是很到位的. 但是有一点,在Android上尽量不要使用同步的方式,而尽量采用异步的方式.
原因有2点: 1.同步的方式的Retrofit需要子线程中执行. 稍微加大了工作量. (需要自己建立线程池或者子线程,更新UI的操作又得通过Handler提交给主线程执行)
      2.同步的方式的Retrofit的异常处理很不好.因为抛出的都是RuntimeException.所以不会提示用户手动捕捉.在Android上子线程崩溃也会引起应用崩溃,很不好.
      而异步方式CallBack的failure()方法可以使开发者方便的对错误进行特殊处理.也不会使异常向外传递.对开发者友好的多.
如果想了解Retrofit的实现原理,可以看后面的文章.
 
posted @ 2015-05-07 14:52  laiqurufeng  阅读(2690)  评论(0编辑  收藏  举报