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接口注解
第一類:網(wǎng)絡請求方法
@HTTP(method = "GET", path = "blog/{id}", hasBody = false)
第二類:標記
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ù)
詳細說明
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ù)放到硬盤中