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