Retrofit源碼筆記

Retrofit整個流程

不是網(wǎng)絡請求框架,只是對網(wǎng)絡框架的封裝,底層還是通過okhttp實現(xiàn)
Retrofit--->ServiceMethod(CallFactory,CallAdapterFactory,ConverterFactory)--->OkHttpCall--->CallAdapter--->Convert--->callbackExecutor)

1.首先創(chuàng)建Retrofit類,這是Retrofit框架的整個的門面類,是個入口哨苛,可以對網(wǎng)絡參數(shù)進行配置,通過build模式币砂;在創(chuàng)建build時建峭,內(nèi)部有一個非常重要的類,ServiceMethod類决摧。
2.ServiceMethod對應我們應用程序中自己寫好的接口類中的一個方法亿蒸;我們會通過動態(tài)代理模式將我們定義好的接口中的一些參數(shù),方法最終轉換成一個個的http請求掌桩;并且負責解析我們方法中的注解边锁,生成我們需要的request對象;并生成了三個非常重要的工廠類:CallAdapter工廠(生產(chǎn)calladapter波岛,而calladapter是我們網(wǎng)絡請求Call的適配器茅坛,retrofit默認情況下Call是okhttpCall,CallAdapter的作用就是將我們的okhttpCall轉換成適應不同平臺的的模式)盆色,Convert工廠(生成我們的數(shù)據(jù)轉換器Convert灰蛙,用它將我們網(wǎng)絡返回的response轉換成我們能使用的java對象,默認是Gson)隔躲;Call工廠(創(chuàng)建call請求類,一個個的http請求會被抽象封裝成Call類物延,Call工廠就是用來創(chuàng)建http請求)宣旱。通過ServiceMethod創(chuàng)建出我們的OkHttpCall

Retrofit請求過程7步驟
1.配置依賴庫
2.編寫返回數(shù)據(jù)bean類
3.創(chuàng)建用于描述網(wǎng)絡請求的接口:
創(chuàng)建一個用于描述我們整個網(wǎng)絡請求的接口,retrofit將我們每一個http請求抽象成了java接口叛薯,同時通過注解方式描述我們網(wǎng)絡請求參數(shù)和配置我們整個網(wǎng)絡請求參數(shù)浑吟,
通過動態(tài)代理模式將我們整個接口的注解翻譯成了一個http請求笙纤。接口中每個方法參數(shù)都必須使用注解參數(shù),否則會報錯
4.創(chuàng)建retrofit實例组力。通過構造者模式省容,配置baseurl,convertFactory燎字,CallAdapterFactory(RxJava,java8...)等
5.創(chuàng)建網(wǎng)絡接口實例:retrofit.create();
6.發(fā)送網(wǎng)絡請求
7.處理服務器返回的數(shù)據(jù)

代理模式:為其他對象提供一種代理候衍,用以控制對這個對象的訪問
靜態(tài)代理:代理類和被代理類都實現(xiàn)同一個接口滨砍,代理類包含被代理類的引用

動態(tài)代理
代理類在程序運行時創(chuàng)建的代理方式惋戏;相比靜態(tài)代理响逢,可以很方便的對代理類進行統(tǒng)一的處理龄句。有兩種動態(tài)代理方式
1).jdk動態(tài)代理:需要客戶端寫輔助類接口;代理類需要實現(xiàn)接口职抡;比較高效
2).CGLIB:直接修改字節(jié)碼
InvocationHandler:
每個代理類的對象都會關聯(lián)一個表示內(nèi)部處理邏輯的InvocationHandler接口的實現(xiàn)缚甩。
invoke方法的參數(shù)可以獲取參數(shù)
invoke方法的返回值被返回給使用者

retrofit網(wǎng)絡通信流程&步驟
1).創(chuàng)建retrofit實例
2).定義一個網(wǎng)絡請求接口并為接口中的方法添加注解
3).通過動態(tài)代理生成網(wǎng)絡請求對象
4).通過網(wǎng)絡請求適配器將網(wǎng)絡請求對象進行平臺適配
5).通過網(wǎng)絡請求執(zhí)行器(Call)發(fā)送網(wǎng)絡請求
6).通過數(shù)據(jù)轉換器解析數(shù)據(jù)
7).通過回調(diào)執(zhí)行器切換線程
8).用戶在主線程處理結果

Retrofit類簡介:

使用

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("")
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
MyInterface myInterface = retrofit.creat(MyInterface.class);
Call call = myInterface.getCall();
call.enqueue(new retrofit2.Callback(){...});

Retrofit 類源碼分析

/**
key值是Method,也就是我們http請求方法郊丛,ServiceMethod也就是我們接口中的方法及注解导盅,解析后得到的對象白翻;
serviceMethodCache 主要是適用于緩存的:例如存儲網(wǎng)絡請求的一些配置,還有網(wǎng)絡請求的方法纪蜒,數(shù)據(jù)轉換器纯续,網(wǎng)絡請求
適配器等等
**/
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
/**
callFactory 網(wǎng)絡請求的okhttp的工廠,默認生產(chǎn)okhttpclient
**/
final okhttp3.Call.Factory callFactory;
/**
網(wǎng)絡請求的基地址
**/
final HttpUrl baseUrl;
/**
數(shù)據(jù)轉換器工廠的集合
**/
final List<Converter.Factory> converterFactories;

/**
*網(wǎng)絡請求適配器集合,例如將Call轉換成Rxjava支持的Call
**/
final List<CallAdapter.Factory> adapterFactories;

/**
*用于執(zhí)行回調(diào)倦炒,默認MainThreadExecutor
**/
final Executor callbackExecutor;

/**
 *標志位逢唤,是否需要立即解析接口中的方法
**/
final boolean validateEagerly;

Retrofit.Builder類

public static final class Builder {
/**
 *適配的平臺,Android著恩,IOS,JAVA8
**/
    private final Platform platform;
    private okhttp3.Call.Factory callFactory;
    private HttpUrl baseUrl;
    private final List<Converter.Factory> converterFactories = new ArrayList<>();
    private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
    private Executor callbackExecutor;
    private boolean validateEagerly;
    public Builder() {
      this(Platform.get());
    }

    public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
//默認的是okhttpclient
        callFactory = new OkHttpClient();
      }

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
//android平臺下返回MainThreadExecutor,具體見下面platform代碼
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
//添加平臺支持的默認轉換器工廠
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }  
}


/**
* 支持的平臺
**/
class Platform {
  private static final Platform PLATFORM = findPlatform();
  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) {
    }
    try {
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }
/**
*支持的android平臺
**/
static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }
//默認的回調(diào)執(zhí)行
    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());
      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }
}

RxJava2CallAdapterFactory內(nèi)部構造與工作原理

CallAdapter作用就是把我們Retrofit中的Call泛型對象轉換成java對象纵顾,通過這個java對象來進行別的操作(UI的顯示施逾,后臺的數(shù)據(jù)運作等等)音念。Call<T>--->網(wǎng)絡請求--->converter--->java對象整葡,retrofit中的Call是對okhttp中的Call進行了封裝

public interface CallAdapter<R, T> {
  /**用于http請求返回解析后的類型
   */
  Type responseType();

  /** T是轉換成接口的返回類型(如果是Rxjava,T則為接口中的Observable或者Flowable)遭居;參數(shù)Call就是okhttpCall的一個對象實例
   **/
  T adapt(Call<R> call);

  /** 例如Rxjava2CallAdapterFactory需要繼承這個Factory,并添加到Retrofit中集合中
   * Creates {@link CallAdapter} instances based on the return type of {@linkplain
   * Retrofit#create(Class) the service interface} methods.
   */
  abstract class Factory {
    /**根據(jù)接口的返回類型注解類型來得到實際需要的Adapter
     * Returns a call adapter for interface methods that return {@code returnType}, or null if it
     * cannot be handled by this factory.
     */
    public abstract CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
        Retrofit retrofit);

    /**
     * Extract the upper bound of the generic parameter at {@code index} from {@code type}. For
     * example, index 1 of {@code Map<String, ? extends Runnable>} returns {@code Runnable}.
     */
    protected static Type getParameterUpperBound(int index, ParameterizedType type) {
      return Utils.getParameterUpperBound(index, type);
    }

    /**獲取我們原始的類型
     * Extract the raw class type from {@code type}. For example, the type representing
     * {@code List<? extends Runnable>} returns {@code List.class}.
     */
    protected static Class<?> getRawType(Type type) {
      return Utils.getRawType(type);
    }
  }
}
RxJava2CallAdapterFactory源碼解析

實現(xiàn)CallAdapter.Factory抽象類--->注冊CallAdatper(retrofit中addCallAdapterFactory)--->CallAdapter.Factory.get()來進行獲取CallAdapter--->adapt()方法將Call轉換成每一個平臺使用的類型

public final class RxJava2CallAdapterFactory extends CallAdapter.Factory {
 

  @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
//Factory中的getRawType();返回原始的數(shù)據(jù)類型岳颇;之后一串代碼都是判斷rawType是否是Rxjava支持的類型;最終會返
回我們一個CallAdapter的具體實現(xiàn)對象,然后調(diào)用adapt來進行Call請求的轉換
    Class<?> rawType = getRawType(returnType);
     .......
    return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,
        isSingle, isMaybe, false);
  }

/**
* 舉個栗子:RxJava2CallAdapter中對Call轉換成Observable
**/
final class RxJava2CallAdapter<R> implements CallAdapter<R, Object> {

@Override public Object adapt(Call<R> call) {
    Observable<Response<R>> responseObservable = isAsync
        ? new CallEnqueueObservable<>(call)
        : new CallExecuteObservable<>(call);

    Observable<?> observable;
   ......
    return observable;
  }
}
Retrofit網(wǎng)絡請求接口實例解析

還是按之前使用的例子來看

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("")
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
//使用動態(tài)代理生成接口的代理類
MyInterface myInterface = retrofit.creat(MyInterface.class);
/**代理類調(diào)用Proxy.newProxyInstance()方法去進行攔截,調(diào)用InvocationHandler中的
invoke方法來進行實際的操作新博,返回CallAdapter轉換okhttpCall后的適應不同平臺的網(wǎng)絡請求
本例子中返回的是Call對象,如果支持Rxjava可能返回Flowable等
**/
Call call = myInterface.getCall();
call.enqueue(new retrofit2.Callback(){...});

在初始化Retrofit之后,調(diào)用retrofit.create();來看下create中的方法

  public <T> T create(final Class<T> service) {
//對接口的字節(jié)碼進行驗證
    Utils.validateServiceInterface(service);
//validateEagerly標志位涩蜘,代表是否需要提前來驗證同诫,解析我們的接口
    if (validateEagerly) {
//serviceMethodCache中如果有緩存直接讀取緩存叮盘,沒有緩存則對接口中的所有方法解析成各種ServiceMethod,并存入
serviceMethodCache中;詳見下面的代碼
      eagerlyValidateMethods(service);
    }

//通過動態(tài)代理來創(chuàng)建我們網(wǎng)絡請求的實例,newProxyInstance會傳進來一個class對象丙唧,會生成一個實例(代理類)培漏,每當
我們執(zhí)行我們代理類的方法的時候就會調(diào)用new InvocationHandler()中的invoke方法,用于解析我們接口方法注解等操作
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();

          @Override public Object invoke(Object proxy, Method method, Object[] args)
              throws Throwable {
           ...
//最核心的三行代碼,下一小節(jié)著重講這三行代碼
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

private void eagerlyValidateMethods(Class<?> service) {
    Platform platform = Platform.get();
    for (Method method : service.getDeclaredMethods()) {
      if (!platform.isDefaultMethod(method)) {
        loadServiceMethod(method);
      }
    }
  }

  ServiceMethod<?, ?> loadServiceMethod(Method method) {
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
    if (result != null) return result;
//設置線程同步鎖
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
//創(chuàng)建新的ServiceMethod對象珊佣,并放入緩存池中
        result = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

Retrofit中serviceMethod對象解析

動態(tài)代理中invoke中最核心三行代碼
//loadServiceMethod看上文代碼
ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);

ServiceMethod類源碼分析

//包含我們訪問網(wǎng)絡的所有基本信息
final class ServiceMethod<R, T> {
//用于生產(chǎn)我們的網(wǎng)絡請求call彩扔,默認是okhttpCall(實現(xiàn)Call<T>接口),對okhttp中的Call封裝
  final okhttp3.Call.Factory callFactory;
//網(wǎng)絡請求適配器敦捧,適應不同平臺
  final CallAdapter<R, T> callAdapter;

  private final HttpUrl baseUrl;
  private final Converter<ResponseBody, R> responseConverter;
//網(wǎng)絡請求的方法兢卵,get秽荤,post,put等
  private final String httpMethod;
  private final String relativeUrl;
//網(wǎng)絡http的請求頭
  private final Headers headers;
//網(wǎng)絡請求的http報文的body類型
  private final MediaType contentType;
  private final boolean hasBody;
  private final boolean isFormEncoded;
  private final boolean isMultipart;
//非常重要柠横,方法參數(shù)的處理器窃款,我們在定義接口的時候,參數(shù)跟注解都需要通過這個處理器處理
  private final ParameterHandler<?>[] parameterHandlers;

static final class Builder<T, R> {
    final Retrofit retrofit;
//網(wǎng)絡請求的方法(接口中的方法)
    final Method method;
//網(wǎng)絡請求方法上的注解
    final Annotation[] methodAnnotations;
//網(wǎng)絡請求方法中參數(shù)的注解的內(nèi)容
    final Annotation[][] parameterAnnotationsArray;
//網(wǎng)絡接口請求方法中參數(shù)的類型
    final Type[] parameterTypes;
Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations();
      this.parameterTypes = method.getGenericParameterTypes();
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }
}

/**
*   總結:build()方法根據(jù)我們的返回值類型和方法中的注解來從我們的網(wǎng)絡請求適配器工廠集合和我們的數(shù)據(jù)轉換器工廠
集合中分別獲取到我們所需要的網(wǎng)絡請求適配器和response數(shù)據(jù)轉換器牍氛,然后根據(jù)我們參數(shù)晨继,注解來獲取我們需要解析的
參數(shù),最后調(diào)用parseParameter方法來解析我們接口中的參數(shù)
**/
public ServiceMethod build() {
//createCallAdapter()代碼主要是通過循環(huán)retrofit中的adapterFactories中CallAdapter.Factory.get方法獲取不同平臺的CallAdapter
      callAdapter = createCallAdapter();
      responseType = callAdapter.responseType();
//創(chuàng)建數(shù)據(jù)轉換器,通過循環(huán)retrofit中的converterFactories中Converter.Factory.responseBodyConverter方法獲取不同平臺的Converter
      responseConverter = createResponseConverter();

      for (Annotation annotation : methodAnnotations) {
//解析方法上的注解
        parseMethodAnnotation(annotation);
      }

      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        Type parameterType = parameterTypes[p];
      Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
//對方法中參數(shù)及注解的解析搬俊,有Path蜒茄,Query等類都是繼承ParseParameter
       parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }
      return new ServiceMethod<>(this);
    }

/**
*  創(chuàng)建網(wǎng)絡請求適配器
**/
     private CallAdapter<T, R> createCallAdapter() {
//獲取方法返回值,例如Obserable<>
      Type returnType = method.getGenericReturnType();
//獲取方法注解
      Annotation[] annotations = method.getAnnotations();
//通過retrofit中的adapterFactories中CallAdapter.Factory.get方法獲取不同平臺的CallAdapter
      return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
      }

/**
*  創(chuàng)建網(wǎng)絡請求數(shù)據(jù)轉換器
**/
private Converter<ResponseBody, T> createResponseConverter() {
     Annotation[] annotations = method.getAnnotations();
     return retrofit.responseBodyConverter(responseType, annotations);
     }

}
Retrofit中okHttpCall對象和adapt返回對象解析

繼續(xù)看之前的三行重要代碼伙判,上文解析了ServiceMethod類,接下來看OkHttpCall
retrofit同步請求流程:對我們每個網(wǎng)絡請求參數(shù)利用ParameterHandler來解析;根據(jù)創(chuàng)建好的ServiceMethod對象來創(chuàng)建http請求中需要的request對象楷力;okhttp發(fā)送網(wǎng)絡請求献联;Converter進行網(wǎng)絡響應轉換成java對象运悲。retrofit主要通過接口跟注解來對http請求做了包裝封裝宠能,讓我們在使用只要把焦點放在接口的創(chuàng)建上,通過接口來配置方法跟參數(shù),通過動態(tài)代理將接口方法轉換成ServiceMethod對象,通過serviceMethod來獲取我們想要的信息

動態(tài)代理中invoke中最核心三行代碼
//loadServiceMethod看上文代碼
ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
//最終調(diào)用CallAdapter中的adapt方法轉換怔蚌,具體看下RxJava2CallAdapter
return serviceMethod.callAdapter.adapt(okHttpCall);

OkHttpCall源碼

對okhtt.Call的封裝
final class OkHttpCall<T> implements Call<T> {
  private final ServiceMethod<T, ?> serviceMethod;
//請求參數(shù)
  private final Object[] args;
//狀態(tài)標志位,是否要去取消請求
  private volatile boolean canceled;

  // 實際的網(wǎng)絡請求類
  private okhttp3.Call rawCall;
//異常拋出
  private Throwable creationFailure; // Either a RuntimeException or IOException.
  //用在異步方法中判斷邏輯
  private boolean executed;

  OkHttpCall(ServiceMethod<T, ?> serviceMethod, Object[] args) {
    this.serviceMethod = serviceMethod;
    this.args = args;
  }

//返回okhttp中的Request
@Override public synchronized Request request() {
    Request request = serviceMethod.toRequest(args)鲸湃;
    rawCall = createRawCall();
return rawCall.request();
}

@Override public void enqueue(final Callback<T> callback) {
......
}

@Override public Response<T> execute() throws IOException {
    okhttp3.Call call;
    call = rawCall = createRawCall();
     return parseResponse(call.execute());
  }

//創(chuàng)建真正的網(wǎng)絡請求Call,對網(wǎng)絡請求接口中的每個參數(shù)調(diào)用parameterHandler來解析鲜屏,然后通
//過serviceMethod對象生成request务热,并生成okhttp中的Call
private okhttp3.Call createRawCall() throws IOException {
//serviceMethod中通過parameterHandlers去解析參數(shù)生成Request
    Request request = serviceMethod.toRequest(args);
    okhttp3.Call call = serviceMethod.callFactory.newCall(request);
   return call;
  }

//解析請求回來后的數(shù)據(jù)
 Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
//調(diào)用serviceMethod中的轉換器responseConverter.convert(body);
    T body = serviceMethod.toResponse(catchingBody);
      return Response.success(body, rawResponse);
}

}

Retrofit涉及的別的知識點總結

Retrofit接口注解

retrofit注解類型.png
第一類:網(wǎng)絡請求方法
retrofit網(wǎng)絡請求方法.png

@HTTP(method = "GET", path = "blog/{id}", hasBody = false)

第二類:標記
retrofit標記注解.png

a. @FormUrlEncoded
作用:表示發(fā)送form-encoded的數(shù)據(jù)
每個鍵值對需要用@Filed來注解鍵名赖晶,隨后的對象需要提供值了牛。

/**
 *表明是一個表單格式的請求(Content-Type:application/x-www-form-urlencoded)
 * <code>Field("username")</code> 表示將后面的 <code>String name</code> 中name的取值作為 username 的值
*/
@POST("/form")
@FormUrlEncoded
Call<ResponseBody> testFormUrlEncoded1(@Field("username") String name, @Field("age") int age);

b. @Multipart
作用:表示發(fā)送form-encoded的數(shù)據(jù)(適用于 有文件 上傳的場景)
每個鍵值對需要用@Part來注解鍵名鹰祸,隨后的對象需要提供值。

/**
* {@link Part} 后面支持三種類型密浑,{@link RequestBody}台夺、{@link okhttp3.MultipartBody.Part} 冤灾、任意類型
* 除 {@link okhttp3.MultipartBody.Part} 以外席噩,其它類型都必須帶上表單字段({@link okhttp3.MultipartBody.Part} 中已經(jīng)包含了表單字段的信息)
*/
@POST("/form")
@Multipart
Call<ResponseBody> testFileUpload1(@Part("name") RequestBody name, @Part("age") RequestBody age, @Part MultipartBody.Part file);


//具體使用
GetRequest_Interface service = retrofit.create(GetRequest_Interface.class);
 // @FormUrlEncoded 
Call<ResponseBody> call1 = service.testFormUrlEncoded1("Carson", 24);

//  @Multipart
RequestBody name = RequestBody.create(textType, "Carson");
RequestBody age = RequestBody.create(textType, "24");

MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", "test.txt", file);
Call<ResponseBody> call3 = service.testFileUpload1(name, age, filePart);

第三類:網(wǎng)絡請求參數(shù)


retrofit網(wǎng)絡請求參數(shù)注解.png

詳細說明
a. @Header & @Headers

作用:添加請求頭 &添加不固定的請求頭
具體使用如下:

// @Header
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)

// @Headers
@Headers("Authorization: authorization")
@GET("user")
Call<User> getUser()

// 以上的效果是一致的芯砸。
// 區(qū)別在于使用場景和使用方式
// 1. 使用場景:@Header用于添加不固定的請求頭萧芙,@Headers用于添加固定的請求頭
// 2. 使用方式:@Header作用于方法的參數(shù);@Headers作用于方法

b. @Body
作用:以 Post方式 傳遞 自定義數(shù)據(jù)類型 給服務器
特別注意:如果提交的是一個Map假丧,那么作用相當于 @Field
不過Map要經(jīng)過 FormBody.Builder 類處理成為符合 Okhttp 格式的表單双揪,如:

FormBody.Builder builder = new FormBody.Builder();
builder.add("key","value");

c. @Field & @FieldMap
作用:發(fā)送 Post請求 時提交請求的表單字段
具體使用:與 @FormUrlEncoded 注解配合使用

public interface GetRequest_Interface {
        /**
         *表明是一個表單格式的請求(Content-Type:application/x-www-form-urlencoded)
         * <code>Field("username")</code> 表示將后面的 <code>String name</code> 中name的取值作為 username 的值
         */
        @POST("/form")
        @FormUrlEncoded
        Call<ResponseBody> testFormUrlEncoded1(@Field("username") String name, @Field("age") int age);

/**
         * Map的key作為表單的鍵
         */
        @POST("/form")
        @FormUrlEncoded
        Call<ResponseBody> testFormUrlEncoded2(@FieldMap Map<String, Object> map);

}

// 具體使用
         // @Field
        Call<ResponseBody> call1 = service.testFormUrlEncoded1("Carson", 24);

        // @FieldMap
        // 實現(xiàn)的效果與上面相同,但要傳入Map
        Map<String, Object> map = new HashMap<>();
        map.put("username", "Carson");
        map.put("age", 24);
        Call<ResponseBody> call2 = service.testFormUrlEncoded2(map);

d. @Part & @PartMap
作用:發(fā)送 Post請求 時提交請求的表單字段
與@Field的區(qū)別:功能相同包帚,但攜帶的參數(shù)類型更加豐富渔期,包括數(shù)據(jù)流,所以適用于 有文件上傳 的場景

e. @Query和@QueryMap

  • 作用:用于 @GET 方法的查詢參數(shù)(Query = Url 中 ‘?’ 后面的 key-value)

    如:url = http://www.println.net/?cate=android,其中疯趟,Query = cate

  • 具體使用:配置時只需要在接口方法中增加一個參數(shù)即可:

  @GET("/")    
   Call<String> cate(@Query("cate") String cate);
}

// 其使用方式同 @Field與@FieldMap拘哨,這里不作過多描述

Retrofit設計模式

構建者模式:將一個復雜對象的構建跟表示相分離,主要是對象創(chuàng)建的復雜程度對我們用戶來說是不需要知道的信峻,只需要調(diào)用builder內(nèi)部類通過它的鏈式調(diào)用來初始化倦青。

工廠模式:在retrofit中CallAdapter.Factory有get方法,獲取不同的CallAdapter盹舞;不同的網(wǎng)絡適配器工廠只要集成這個Factory并實現(xiàn)get方法就能生產(chǎn)自己平臺的CallAdapter产镐。Platform中的findPlatform也是個靜態(tài)的工廠方法。

外觀模式:門戶模式踢步,外部與一個子系統(tǒng)的通信必須通過一個統(tǒng)一的外觀對像來進行癣亚。Retrofit對外統(tǒng)一的對外類就是Retrofit

策略模式:不使用策略時,一般用if 获印;else if判斷不同的方法策略述雾;以后如果需要添加新的方法策略時需要改以前的代碼,維護成本高兼丰。一般有幾個角色:1.Context(上下文)玻孟;2.抽象的策略類Strategy;3.具體的策略實現(xiàn)類ConcreteStrategyA鳍征。context會使用Strategy接口來調(diào)用具體的ConcreteStrategy來實現(xiàn)方法取募。例如CallAdapter類(Strategy);Retrofit(Context)蟆技;RxjavaCallAdapter(ConcreteStrategy)。工廠模式側重于生成不同的對象斗忌;策略模式側重于不同對象方法的實現(xiàn)质礼。

適配器模式:將接口轉換成客戶端希望的接口,使本不兼容的類能一起工作。例如CallAdapter類中的adapt方法织阳,將我們的okhttpcall適配成適應不同平臺的網(wǎng)絡請求call;okhttpcall只有執(zhí)行網(wǎng)絡請求功能眶蕉,但retrofit是支持很多平臺的,請求有各自的特性唧躲,通過適配器將okhttpcall適配成適配不同平臺的Call

觀察者模式:建立一個對象跟多個對象之間的依賴關系造挽,當一個對象變化時會自動通知觀察它的對象進行改變。

Hook

通過某種手段對一件事物進行改頭換面弄痹,從而劫持Hook的目標來以達到控制目標的行為的目的饭入;兩種方式實現(xiàn):反射跟動態(tài)代理

MVP,MVC

mvc:Model View Controller肛真,將我們的業(yè)務邏輯谐丢,數(shù)據(jù)顯示,界面相分離。
mvp跟mvc最大區(qū)別就是mvc是允許Model跟View交互的乾忱,而MVP則不允許View跟Model交互讥珍;
mvp缺點:P層臃腫,V跟P的耦合窄瘟,接口顆粒度(接口過多過少都有影響)

SharedPreferences

跨進程讀戎缘琛:設置模式為Context.MODE_MULTI_PROCESS(該屬性為deprecated),但有數(shù)據(jù)安全問題蹄葱,官方推薦Contentprovider氏义。

SharedPreferences文件的一種,底層采用xml文件新蟆,安卓系統(tǒng)對xml文件的讀取有緩存策略觅赊,在內(nèi)存中會有xml的一份緩存,導致多進程環(huán)境下每個進程都會保存一份SharedPreferences文件琼稻,這樣就會讀寫的時候造成讀寫不一致吮螺。

apply()和commit()區(qū)別:apply是一個沒有返回值的方法,將我們修改的數(shù)據(jù)提交到內(nèi)存(commitToMemory)帕翻,并異步把數(shù)據(jù)提交到硬盤(enqueueDiskWrite(runable))鸠补。commit方式有返回值boolean,是同步將我們數(shù)據(jù)放到硬盤中

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嘀掸,一起剝皮案震驚了整個濱河市紫岩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌睬塌,老刑警劉巖泉蝌,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異揩晴,居然都是意外死亡勋陪,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門硫兰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來诅愚,“玉大人,你說我怎么就攤上這事劫映∥バⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵泳赋,是天一觀的道長雌桑。 經(jīng)常有香客問我,道長摹蘑,這世上最難降的妖魔是什么筹燕? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上撒踪,老公的妹妹穿的比我還像新娘过咬。我一直安慰自己,他們只是感情好制妄,可當我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布掸绞。 她就那樣靜靜地躺著,像睡著了一般耕捞。 火紅的嫁衣襯著肌膚如雪衔掸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天俺抽,我揣著相機與錄音敞映,去河邊找鬼。 笑死磷斧,一個胖子當著我的面吹牛振愿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播弛饭,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼冕末,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了侣颂?” 一聲冷哼從身側響起档桃,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎憔晒,沒想到半個月后藻肄,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡拒担,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年仅炊,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片澎蛛。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蜕窿,靈堂內(nèi)的尸體忽然破棺而出谋逻,到底是詐尸還是另有隱情,我是刑警寧澤桐经,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布毁兆,位于F島的核電站,受9級特大地震影響阴挣,放射性物質發(fā)生泄漏气堕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望茎芭。 院中可真熱鬧揖膜,春花似錦、人聲如沸梅桩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽宿百。三九已至趁仙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間垦页,已是汗流浹背雀费。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留痊焊,地道東北人盏袄。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像宋光,于是被迫代替她去往敵國和親貌矿。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,884評論 2 354

推薦閱讀更多精彩內(nèi)容