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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM