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的实现原理,可以看后面的文章.