国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

Android app開發(fā)中Retrofit框架的初步上手使用

2020-04-11 10:47:16
字體:
供稿:網(wǎng)友

Retrofit 2.0
先來說一下Retrofit 2.0版本中一些引人注意的地方。

在Retrofit 2.0中,最大的改動莫過于減小庫的體積,首先,Retrofit 2.0去掉了對所有的HTTP客戶端的兼容,而鐘情于OkHttpClient一個,極大地減少了各種適配代碼,原因一會兒說;其次,拆庫,比如將對RxJava的支持設(shè)置為可選(需要額外引入庫);再比如將各個序列化反序列化轉(zhuǎn)換器支持設(shè)置為可選(需要額外引入庫)。于2.0拋棄HttpClient和HttpURLConnection,為了減小庫體積是一方面,另外一個重要的原因作為一個專門為Android&Java 應用量身打造的Http棧,OkHttpClient越來越受到各個大的開源項目的青睞,畢竟它本身就是開源的。

此外,OkHttpClient與HttpClient相比,它最大的改進是自帶工作線程池,所以上層應用無需自己去維護復雜的并發(fā)模型,而HttpClient僅僅提供了一個線程安全的類,所以還需要上層應用去處理并發(fā)的邏輯(實際上Volley一部分工作就是干這個)。從這個角度來說,Retrofit得益于OkHttpClient的優(yōu)勢,較之于Volley是一種更加先進的網(wǎng)絡(luò)框架。

2016219161645807.png (796×402)

由于Retrofit不需要去關(guān)心并發(fā)工作線程的維護,所以它可以全力關(guān)注于如何精簡發(fā)送一個請求的代價,實際上使用Retrofit發(fā)送一個請求實在是太easy了!

 

簡單示例

首先定義請求接口,即程序中都需要什么請求操作

public interface GitHubService { @GET("/users/{user}/repos") List<Repo> listRepos(@Path("user") String user);}

 然后通過RestAdapter生成一個剛才定義的接口的實現(xiàn)類,使用的是動態(tài)代理。

RestAdapter restAdapter = new RestAdapter.Builder()  .setEndpoint("https://api.github.com")  .build(); GitHubService service = restAdapter.create(GitHubService.class);

現(xiàn)在就可以調(diào)用接口進行請求了

List<Repo> repos = service.listRepos("octocat");

使用就是這么簡單,請求時直接調(diào)用接口就行了,甚至不用封裝參數(shù),因為參數(shù)的信息已經(jīng)在定義接口時通過Annotation定義好了。

從上面的例子可以看到接口直接返回了需要的Java類型,而不是byte[]或String,解析數(shù)據(jù)的地方就是Converter,這個是可以自定義的,默認是用Gson解析,也就是說默認認為服務(wù)器返回的是Json數(shù)據(jù),可以通過指定不同的Convert使用不同的解析方法,如用Jackson解析Json,或自定義XmlConvert解析xml數(shù)據(jù)。

Retrofit的使用就是以下幾步:

  • 定義接口,參數(shù)聲明,Url都通過Annotation指定
  • 通過RestAdapter生成一個接口的實現(xiàn)類(動態(tài)代理)
  • 調(diào)用接口請求數(shù)據(jù)
  • 接口的定義要用用Rtrofit定義的一些Annotation,所以先看一下Annotation的。

Annotation

以上面的示例中的接口來看

@GET("/group/{id}/users")List<User> groupList(@Path("id") int groupId);

 先看@GET

/** Make a GET request to a REST path relative to base URL. */@Documented@Target(METHOD)@Retention(RUNTIME)@RestMethod("GET")public @interface GET { String value();}


 

@GET本身也被幾個Anotation注解,@Target表示@GET注解是用于方法的,value方法就返回這個注解的value值,在上例中就是/group/{id}/users,然后就是@RestMethod

@Documented@Target(ANNOTATION_TYPE)@Retention(RUNTIME)public @interface RestMethod { String value(); boolean hasBody() default false;}

RestMethod是一個用于Annotation的Annotation,比如上面的例子中用來注解的@GET,value方法就返回GET,hasBody表示是否有Body,對于POST這個方法就返回true

@Documented@Target(METHOD)@Retention(RUNTIME)@RestMethod(value = "POST", hasBody = true)public @interface POST { String value();}


 

Retrofit的Annotation包含請求方法相關(guān)的@GET、@POST、@HEAD、@PUT、@DELETA、@PATCH,和參數(shù)相關(guān)的@Path、@Field、@Multipart等。

定義了Annotation要就有解析它的方法,在Retrofit中解析的位置就是RestMethodInfo,但在這之前需要先看哪里使用了RestMethodInfo,前面說了Retrofit使用了動態(tài)代理生成了我們定義的接口的實現(xiàn)類,而這個實現(xiàn)類是通過RestAdapter.create返回的,所以使用動態(tài)代理的位置就是RestAdapter,接下來就看一下RestAdapter。

RestAdapter

RestAdapter restAdapter = new RestAdapter.Builder()  .setEndpoint("https://api.github.com")  .build();GitHubService service = restAdapter.create(GitHubService.class);public RestAdapter build() { if (endpoint == null) {  throw new IllegalArgumentException("Endpoint may not be null."); }  ensureSaneDefaults();  return new RestAdapter(endpoint, clientProvider, httpExecutor, callbackExecutor,   requestInterceptor, converter, profiler, errorHandler, log, logLevel);}


 

setEndPoint就不說了,接口中定義的都是相對Url,EndPoint就是域名,build方法調(diào)用ensureSaneDefaults()方法,然后就構(gòu)造了一個RestAdapter對象,構(gòu)造函數(shù)的參數(shù)中傳入了EndPoint外的幾個對象,這幾個對象就是在ensureSaneDefaults()中初始化的。

private void ensureSaneDefaults() { if (converter == null) { converter = Platform.get().defaultConverter(); } if (clientProvider == null) { clientProvider = Platform.get().defaultClient(); } if (httpExecutor == null) { httpExecutor = Platform.get().defaultHttpExecutor(); } if (callbackExecutor == null) { callbackExecutor = Platform.get().defaultCallbackExecutor(); } if (errorHandler == null) { errorHandler = ErrorHandler.DEFAULT; } if (log == null) { log = Platform.get().defaultLog(); } if (requestInterceptor == null) { requestInterceptor = RequestInterceptor.NONE; }}

ensureSaneDefaults()中初始化了很多成員,errorHandler、log就不看了,其他的除了requestInterceptor都是通過Platform對象獲得的,所以要先看下Platform

Platform

private static final Platform PLATFORM = findPlatform(); static final boolean HAS_RX_JAVA = hasRxJavaOnClasspath(); static Platform get() {  return PLATFORM; } private static Platform findPlatform() {  try {   Class.forName("android.os.Build");   if (Build.VERSION.SDK_INT != 0) {    return new Android();   }  } catch (ClassNotFoundException ignored) {  }  if (System.getProperty("com.google.appengine.runtime.version") != null) {   return new AppEngine();  }  return new Base(); }


 

使用了單例的PLATFORM,通過findPlatform()初始化實例,如果是Android平臺就使用Platform.Android,如果是Google AppEngine就使用Platform.AppEngine,否則使用Platform.Base,這些都是Platform的子類,其中AppEngine又是Base的子類。

Platform是一個抽象類,定義了以下幾個抽象方法,這幾個方法的作用就是返回一些RestAdapter中需要要用到成員的默認實現(xiàn)

abstract Converter defaultConverter(); // 默認的Converter,用于將請求結(jié)果轉(zhuǎn)化成需要的數(shù)據(jù),如GsonConverter將JSON請求結(jié)果用Gson解析成Java對象 abstract Client.Provider defaultClient(); // Http請求類,如果是AppEngine就使用`UrlFetchClient`,否則如果有OKHttp就使用OKHttp,如果是Android,2.3以后使用HttpURLConnection,2.3以前使用HttpClient abstract Executor defaultHttpExecutor(); // 用于執(zhí)行Http請求的Executor abstract Executor defaultCallbackExecutor(); // Callback調(diào)用中用于執(zhí)行Callback的Executor(可能是同步的) abstract RestAdapter.Log defaultLog(); // Log接口,用于輸出Log

看完P(guān)latform的接口再看ensureSaneDefaults就清楚了,初始化轉(zhuǎn)化數(shù)據(jù)的Converter、執(zhí)行請求的Client、執(zhí)行請求的Executor、執(zhí)行Callback的Executor、Log輸出類、錯誤處理類和用于在請求前添加額外處理的攔截請求的Interceptor。
Converter默認都是用的GsonConverter,就不看了,defaultClient返回執(zhí)行網(wǎng)絡(luò)請求的Client

Platform.Android

@Override Client.Provider defaultClient() { final Client client; if (hasOkHttpOnClasspath()) {  client = OkClientInstantiator.instantiate(); } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {  client = new AndroidApacheClient(); } else {  client = new UrlConnectionClient(); } return new Client.Provider() {  @Override public Client get() {   return client;  } };}


Platform.Base

@Override Client.Provider defaultClient() { final Client client; if (hasOkHttpOnClasspath()) {  client = OkClientInstantiator.instantiate(); } else {  client = new UrlConnectionClient(); } return new Client.Provider() {  @Override public Client get() {   return client;  } };}

 Platform.AppEngine


@Override Client.Provider defaultClient() { final UrlFetchClient client = new UrlFetchClient(); return new Client.Provider() {  @Override public Client get() {   return client;  } };}

對于Android,優(yōu)先使用OKHttp,否則2.3以后使用HttpUrlConnection,2.3以前使用HttpClient

defaultHttpExecutor就是返回一個Executor,執(zhí)行請求的線程在這個Executor中執(zhí)行,就做了一件事,把線程設(shè)置為后臺線程

defaultCallbackExecutor用于執(zhí)行Callback類型的請求時,提供一個Executor執(zhí)行Callback的Runnable

Platform.Base

@Override Executor defaultCallbackExecutor() {  return new Utils.SynchronousExecutor();}Platform.Android@Override Executor defaultCallbackExecutor() {  return new MainThreadExecutor();}

SynchronousExecutor

static class SynchronousExecutor implements Executor {  @Override public void execute(Runnable runnable) {   runnable.run();  }}

MainThreadExecutor

public final class MainThreadExecutor implements Executor { private final Handler handler = new Handler(Looper.getMainLooper()); @Override public void execute(Runnable r) {  handler.post(r); }}

如果是Android,通過Handler將回調(diào)發(fā)送到主線程執(zhí)行,如果非Android,直接同步執(zhí)行。
Platform看完了,RestAdapter的成員初始化完成,就要看怎么通過RestAdapter.create生成我們定義的接口的實現(xiàn)類了

RestAdapter.create

 public <T> T create(Class<T> service) {  Utils.validateServiceClass(service);  return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },    new RestHandler(getMethodInfoCache(service))); }  Map<Method, RestMethodInfo> getMethodInfoCache(Class<?> service) {  synchronized (serviceMethodInfoCache) {   Map<Method, RestMethodInfo> methodInfoCache = serviceMethodInfoCache.get(service);   if (methodInfoCache == null) {    methodInfoCache = new LinkedHashMap<Method, RestMethodInfo>();    serviceMethodInfoCache.put(service, methodInfoCache);   }   return methodInfoCache;  } }

使用了動態(tài)代理,InvocationHandler是RestHandler,RestHandler有一個參數(shù),是Method->RestMethodInfo的映射,初始化時這個映射是空的。重點就是這兩個了:RestHandler,RestMethodInfo,

@Override public Object invoke(Object proxy, Method method, final Object[] args)  throws Throwable { // If the method is a method from Object then defer to normal invocation. if (method.getDeclaringClass() == Object.class) { // 1  return method.invoke(this, args); }  // Load or create the details cache for the current method. final RestMethodInfo methodInfo = getMethodInfo(methodDetailsCache, method); // 2  if (methodInfo.isSynchronous) { // 3  try {   return invokeRequest(requestInterceptor, methodInfo, args);  } catch (RetrofitError error) {   Throwable newError = errorHandler.handleError(error);   if (newError == null) {    throw new IllegalStateException("Error handler returned null for wrapped exception.",      error);   }   throw newError;  } }  if (httpExecutor == null || callbackExecutor == null) {  throw new IllegalStateException("Asynchronous invocation requires calling setExecutors."); }  // Apply the interceptor synchronously, recording the interception so we can replay it later. // This way we still defer argument serialization to the background thread. final RequestInterceptorTape interceptorTape = new RequestInterceptorTape(); requestInterceptor.intercept(interceptorTape); // 4  if (methodInfo.isObservable) { // 5  if (rxSupport == null) {   if (Platform.HAS_RX_JAVA) {    rxSupport = new RxSupport(httpExecutor, errorHandler);   } else {    throw new IllegalStateException("Observable method found but no RxJava on classpath");   }  }    return rxSupport.createRequestObservable(new Callable<ResponseWrapper>() {   @Override public ResponseWrapper call() throws Exception {    return (ResponseWrapper) invokeRequest(interceptorTape, methodInfo, args);   }  }); }  Callback<?> callback = (Callback<?>) args[args.length - 1]; // 6 httpExecutor.execute(new CallbackRunnable(callback, callbackExecutor, errorHandler) {  @Override public ResponseWrapper obtainResponse() {   return (ResponseWrapper) invokeRequest(interceptorTape, methodInfo, args);  } });  return null; // Asynchronous methods should have return type of void.}

執(zhí)行請求時會調(diào)用RestHandler的invoke方法,如上所示,主要是上面代碼中標注有6點

如果調(diào)用的是Object的方法,不做處理直接調(diào)用。
通過getMethodInfo獲取調(diào)用的Method對應的RestMethodInfo,前面說了,構(gòu)造RestHandler對象時傳進來了一個Method->RestMethodInfo的映射,初始時是空的。

 static RestMethodInfo getMethodInfo(Map<Method, RestMethodInfo> cache, Method method) {  synchronized (cache) {   RestMethodInfo methodInfo = cache.get(method);   if (methodInfo == null) {    methodInfo = new RestMethodInfo(method);    cache.put(method, methodInfo);   }   return methodInfo;  }

在getMethodInfo中判斷如果相應的映射不存在,就建立這個映射,并如名字所示緩存起來 

  • 如果是同步調(diào)用(接口中直接返回數(shù)據(jù),不通過Callback或Observe),直接調(diào)用invokeRequest 
  • 如果是非同步調(diào)用,先通過RequestInterceptorTape記錄攔截請求,記錄后在后臺線程做實際攔截,后面會提到。
  • 如果是Observe請求(RxJava),執(zhí)行第5步,對RxJava不了解,略過 
  • 如果是Callback形式,交由線程池執(zhí)行

接口中的每一個Method有一個對應的RestMethodInfo,關(guān)于接口中Annotation信息的處理就都在這里了

RestMethodInfo

private enum ResponseType {  VOID,  OBSERVABLE,  OBJECT}RestMethodInfo(Method method) {  this.method = method;  responseType = parseResponseType();  isSynchronous = (responseType == ResponseType.OBJECT);  isObservable = (responseType == ResponseType.OBSERVABLE);}

在構(gòu)造函數(shù)中調(diào)用了parseResponseType,parseResponseType解析了方法簽名,根據(jù)方法的返回值類型及最后一個參數(shù)的類型判斷方法的類型是哪種ResponseType

無論是哪種ResponseType,最終都是調(diào)用invokeRequest執(zhí)行實際的請求,接下來依次看下invokeRequest的執(zhí)行步驟

RestAdapter.invokeRequest

第一步是調(diào)用methodInfo.init()解析調(diào)用的方法,方法里有做判斷,只在第一次調(diào)用時解析,因為處一次解析后這個對象就被緩存起來了,下次調(diào)同一個方法時可以直接使用

 synchronized void init() {  if (loaded) return;  parseMethodAnnotations();  parseParameters();  loaded = true; }

在RestMethodInfo.init中分別調(diào)用

  • parseMethodAnnotations():解析所有方法的Annotation
  • parseParameters():解析所有參數(shù)的Annotation
for (Annotation methodAnnotation : method.getAnnotations()) { Class<? extends Annotation> annotationType = methodAnnotation.annotationType(); RestMethod methodInfo = null; // Look for a @RestMethod annotation on the parameter annotation indicating request method. for (Annotation innerAnnotation : annotationType.getAnnotations()) {  if (RestMethod.class == innerAnnotation.annotationType()) {   methodInfo = (RestMethod) innerAnnotation;   break;  } } ...}

在parseMethodAnnotations中,會獲取方法所有的Annotation并遍歷:
對于每一個Annotation,也會獲取它的Annotation,看它是否是被RestMethod注解的Annotation,如果是,說明是@GET,@POST類型的注解,就調(diào)用parsePath解析請求的Url,requestParam(URL中問號后的內(nèi)容)及Url中需要替換的參數(shù)名(Url中大括號括起來的部分)
尋找Headers Annotation解析Header參數(shù)
解析RequestType:SIMPLE,MULTIPART,F(xiàn)ORM_URL_ENCODED
parseParameters解析請求參數(shù),即參數(shù)的Annotation,@PATH、@HEADER、@FIELD等

第二步是RequestBuilder和Interceptor,這兩個是有關(guān)聯(lián)的,所以一起看。

RequestBuilder requestBuilder = new RequestBuilder(serverUrl, methodInfo, converter);requestBuilder.setArguments(args);requestInterceptor.intercept(requestBuilder);Request request = requestBuilder.build();

先說RequestInterceptor,作用很明顯,當執(zhí)行請求時攔截請求以做一些特殊處理,比如添加一些額外的請求參數(shù)。

/** Intercept every request before it is executed in order to add additional data. */public interface RequestInterceptor { /** Called for every request. Add data using methods on the supplied {@link RequestFacade}. */ void intercept(RequestFacade request); interface RequestFacade {  void addHeader(String name, String value);  void addPathParam(String name, String value);  void addEncodedPathParam(String name, String value);  void addQueryParam(String name, String value);  void addEncodedQueryParam(String name, String value); } /** A {@link RequestInterceptor} which does no modification of requests. */ RequestInterceptor NONE = new RequestInterceptor() {  @Override public void intercept(RequestFacade request) {   // Do nothing.  } };}

RequestInterceptor只有一個方法intercept,接收一個RequestFacade參數(shù),RequestFacade是RequestInterceptor內(nèi)部的一個接口,這個接口的方法就是添加請求參數(shù),Query、Header什么的。大概可以看出RequestInterceptor的作用了,如果RequestFacade表示一個請求相關(guān)的數(shù)據(jù),RequestInteceptor.intercept的作用就是向這個RequestFacade中添加額外Header,Param等參數(shù)。

RequestFacade的一個子類叫RequestBuilder,用來處理Request請求參數(shù),在invokeRequest中會對RequestBuilder調(diào)用intercept方法向RequestBuilder添加額外的參數(shù)。

有一個叫RequestInterceptorTape的類,同時實現(xiàn)了RequestFacade與RequestInterceptor,它的作用是:

當作為RequestFacade使用時作為參數(shù)傳給一個RequestInteceptor,這個RequestInterceptor調(diào)用它的addHeader等方法時,它把這些調(diào)用及參數(shù)記錄下來
然后作為RequestInterceptor使用時,將之前記錄的方法調(diào)用及參數(shù)重新應用到它的intercept參數(shù)RequestFacade中
在RestHandler.invoke中,如果判斷方法的調(diào)用不是同步調(diào)用,就通過下面的兩行代碼將用戶設(shè)置的interceptor需要添加的參數(shù)記錄到RequestInterceptorTape,然后在invokeRequest中再實際執(zhí)行參數(shù)的添加。

// Apply the interceptor synchronously, recording the interception so we can replay it later.// This way we still defer argument serialization to the background thread.final RequestInterceptorTape interceptorTape = new RequestInterceptorTape();requestInterceptor.intercept(interceptorTape);

 RequestBuilder.setArguments()解析調(diào)用接口時的實際參數(shù)。然后通過build()方法生成一個Request對象

第三步執(zhí)行請求,Response response = clientProvider.get().execute(request);

第四步就是解析并分發(fā)請求結(jié)果了,成功請求時返回結(jié)果,解析失敗調(diào)用ErrorHandler給用戶一個自定義異常的機會,但最終都是通過異常拋出到invoke()中的,如果是同步調(diào)用,直接拋異常,如果是Callback調(diào)用,會回調(diào)Callback.failure

CallbackRunnable

請求類型有同步請求,Callback請求,Observable請求,來看下Callback請求:

Callback<?> callback = (Callback<?>) args[args.length - 1];httpExecutor.execute(new CallbackRunnable(callback, callbackExecutor, errorHandler) {  @Override public ResponseWrapper obtainResponse() {   return (ResponseWrapper) invokeRequest(interceptorTape, methodInfo, args);  }});

 Callback請求中函數(shù)最后一個參數(shù)是一個Callback的實例,httpExecutor是一個Executor,用于執(zhí)行Runnable請求,我們看到,這里new了一個CallbackRunnable執(zhí)行,并實現(xiàn)了它的obtainResponse方法,看實現(xiàn):

abstract class CallbackRunnable<T> implements Runnable { private final Callback<T> callback; private final Executor callbackExecutor; private final ErrorHandler errorHandler; CallbackRunnable(Callback<T> callback, Executor callbackExecutor, ErrorHandler errorHandler) {  this.callback = callback;  this.callbackExecutor = callbackExecutor;  this.errorHandler = errorHandler; } @SuppressWarnings("unchecked") @Override public final void run() {  try {   final ResponseWrapper wrapper = obtainResponse();   callbackExecutor.execute(new Runnable() {    @Override public void run() {     callback.success((T) wrapper.responseBody, wrapper.response);    }   });  } catch (RetrofitError e) {   Throwable cause = errorHandler.handleError(e);   final RetrofitError handled = cause == e ? e : unexpectedError(e.getUrl(), cause);   callbackExecutor.execute(new Runnable() {    @Override public void run() {     callback.failure(handled);    }   });  } } public abstract ResponseWrapper obtainResponse();} 

就是一個普通的Runnable,在run方法中首先執(zhí)行obtailResponse,從名字可以看到是執(zhí)行請求返回Response,這個從前面可以看到執(zhí)行了invokeRequest,和同步調(diào)用中一樣執(zhí)行請求。
緊接著就提交了一個Runnable至callbackExecutor,在看Platform時看到了callbackExecotor是通過Platform.get().defaultCallbackExecutor()返回的,Android中是向主線程的一個Handler發(fā)消息

值得注意的事,對于同步調(diào)用,如果遇到錯誤是直接拋異常,而對于異步調(diào)用,是調(diào)用Callback.failure()

Mime

執(zhí)行網(wǎng)絡(luò)請求,需要向服務(wù)端發(fā)送請求參數(shù),如表單數(shù)據(jù),上傳的文件等,同樣需要解析服務(wù)端返回的數(shù)據(jù),在Retrofit中對這些做了封裝,位于Mime包中,也只有封裝了,才好統(tǒng)一由指定的Converter執(zhí)行數(shù)據(jù)的轉(zhuǎn)換

TypedInput和TypedOutput表示輸入輸出的數(shù)據(jù),都包含mimeType,并分別支持讀入一個InputStream或?qū)懙揭粋€OutputStrem

/** * Binary data with an associated mime type. * * @author Jake Wharton (jw@squareup.com) */public interface TypedInput { /** Returns the mime type. */ String mimeType(); /** Length in bytes. Returns {@code -1} if length is unknown. */ long length(); /**  * Read bytes as stream. Unless otherwise specified, this method may only be called once. It is  * the responsibility of the caller to close the stream.  */ InputStream in() throws IOException;}/** * Binary data with an associated mime type. * * @author Bob Lee (bob@squareup.com) */public interface TypedOutput { /** Original filename.  *  * Used only for multipart requests, may be null. */ String fileName(); /** Returns the mime type. */ String mimeType(); /** Length in bytes or -1 if unknown. */ long length(); /** Writes these bytes to the given output stream. */ void writeTo(OutputStream out) throws IOException;}TypedByteArray,內(nèi)部數(shù)據(jù)是一個Byte數(shù)組 private final byte[] bytes; @Override public long length() {  return bytes.length; } @Override public void writeTo(OutputStream out) throws IOException {  out.write(bytes); } @Override public InputStream in() throws IOException {  return new ByteArrayInputStream(bytes); }TypedString,繼承自TypedByteArray,內(nèi)部表示是一樣的public TypedString(String string) {  super("text/plain; charset=UTF-8", convertToBytes(string)); } private static byte[] convertToBytes(String string) {  try {   return string.getBytes("UTF-8");  } catch (UnsupportedEncodingException e) {   throw new RuntimeException(e);  } }

其他的也一樣,從名字很好理解:TypedFile,MultipartTypedOutput,F(xiàn)ormEncodedTypedOutput。

其他

Retrofit對輸入和輸出做了封裝,通過TypedOutput向服務(wù)器發(fā)送數(shù)據(jù),通過TypedInput讀取服務(wù)器返回的數(shù)據(jù)。

通過MultipartTypedOutput支持文件上傳,讀取服務(wù)器數(shù)據(jù)時,如果要求直接返回未解析的Response,Restonse會被轉(zhuǎn)換為TypedByteArray,所以不能是大文件類的

Retrofit支持不同的Log等級,當為LogLevel.Full時會把Request及Response的Body打印出來,所以如果包含文件就不行了。

Retrofit默認使用GsonConverter,所以要想獲取原始數(shù)據(jù)不要Retrofit解析,要么自定義Conveter,要么直接返回Response了,返回Response也比較麻煩

總體來說Retrofit看起來很好用,不過要求服務(wù)端返回數(shù)據(jù)最好要規(guī)范,不然如果請求成功返回一種數(shù)據(jù)結(jié)構(gòu),請求失敗返回另一種數(shù)據(jù)結(jié)構(gòu),不好用Converter解析,接口的定義也不好定義,除非都返回Response,或自定義Converter所有接口都返回String

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 卓资县| 九江市| 榆树市| 洛阳市| 漳浦县| 汝城县| 朝阳区| 鄯善县| 玛纳斯县| 行唐县| 巴中市| 什邡市| 普定县| 巍山| 大安市| 辽源市| 南召县| 香港| 汉沽区| 青浦区| 郓城县| 莫力| 安庆市| 莆田市| 抚顺市| 鄂托克旗| 社会| 长沙县| 轮台县| 五常市| 永新县| 湖南省| 宜阳县| 德州市| 冕宁县| 江安县| 修武县| 北川| 保靖县| 关岭| 开鲁县|