官網(wǎng):https://square.github.io/retrofit/
簡介:
- Retrofit俐东,一個(gè)RESTful( 無狀態(tài) )的HTTP網(wǎng)絡(luò)請求框架(基于OkHttp)( 封裝 )
-
注解配置網(wǎng)絡(luò)請求參數(shù)柔昼,解耦徹底,擴(kuò)展性強(qiáng)
交互示意圖
示例:
- 集成
//build.gradle 引入
implementation 'com.squareup.retrofit2:retrofit:(insert latest version)'
//AndroidManifest.xml 中添加權(quán)限
<uses-permission android:name="android.permission.INTERNET"/>
- 使用
//① 創(chuàng)建Java接口
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
//② Retrofit實(shí)現(xiàn)創(chuàng)建的Java接口
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create()) // 設(shè)置數(shù)據(jù)解析器
.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 支持RxJava平臺(tái)
.build();
GitHubService service = retrofit.create(GitHubService.class);
//③調(diào)用(同步或異步選其一)
Call<List<Repo>> repos = service.listRepos("octocat");
//同步請求
Response<ResponseBody> res = repos.execute();
//或異步請求
repos.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
try {
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
t.printStackTrace();
}
});
注意:
- 1梅垄、Retrofit的Url組合規(guī)則
Retrofit2
的baseUlr
必須以/
(斜線) 結(jié)束,不然會(huì)拋出一個(gè)IllegalArgumentException
仁锯。
所以如果看到別的教程沒有以/
結(jié)束锣杂,那么多半是直接從Retrofit 1.X
照搬過來的。
一畅厢、Retrofit注解
Retrofit注解
1冯痢、@HTTP
- 有三個(gè)屬性:
method
、path
、hasBody
/**
* method 表示請求的方法浦楣,區(qū)分大小寫
* path表示路徑
* hasBody表示是否有請求體
*/
@HTTP(method = "GET", path = "blog/{id}", hasBody = false)
Call<ResponseBody> getBlog(@Path("id") int id);
-
注:
method
的值retrofit
不會(huì)做處理袖肥,所以要自行保證其準(zhǔn)確性,
2振劳、@Path
path注解說明
3椎组、@Header & @Headers
- 添加請求頭 &添加不固定的請求頭
// @Header
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)
// @Headers
@Headers("Authorization: authorization")
@GET("user")
Call<User> getUser()
說明:
以上的效果是一致的。
- 區(qū)別在于使用場景和使用方式
- 使用場景:@Header用于添加不固定的請求頭历恐,@Headers用于添加固定的請求頭
- 使用方式:@Header作用于方法的參數(shù)寸癌;@Headers作用于方法
4、@Body
-
@Body
的參數(shù)如果是一個(gè)Map
弱贼,則作用相當(dāng)于@Field
不過Map要經(jīng)過 FormBody.Builder 類處理成為符合 Okhttp 格式的表單蒸苇,如:
FormBody.Builder builder = new FormBody.Builder();
builder.add("key","value");
5、@Field & @FieldMap吮旅;@Part & @PartMap
-
@Field
與@FieldMap
配合使用填渠,在發(fā)送Post
請求時(shí)提交請求的表單字段 -
@Part
與@Field
的區(qū)別:功能相同,但攜帶的參數(shù)類型更加豐富鸟辅,包括數(shù)據(jù)流氛什,所以適用于 有文件上傳 的場景
6、@Query和@QueryMap
- 用于 @GET 方法的查詢參數(shù)(Query 相當(dāng)于 Url 中 ‘?’ 后面的 key-value)
二匪凉、Converter
-
1枪眉、Retrofit支持多種數(shù)據(jù)解析方式
解析器
注:以上版本可能不是最新版本 -
2、說明:
-
Convert.Factoy
的具體作用就是獲取一個(gè)Convert
-
Converter
是對于Call<T>
中T
的轉(zhuǎn)換 -
addConverterFactory
是有先后順序的再层,如果有多個(gè)ConverterFactory
都支持同一種類型贸铜,那么就是只有第一個(gè)才會(huì)被使用,而GsonConverterFactory
是不判斷是否支持的聂受,所以這里交換了順序還會(huì)有一個(gè)異常拋出蒿秦,原因是類型不匹配。
-
3蛋济、使用:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:4567/")
// 我們自定義的一定要放在Gson這類的Converter前面
.addConverterFactory(StringConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
- 4棍鳖、
Converter
源碼
public interface Converter<F, T> {
// 實(shí)現(xiàn)從 F(rom) 到 T(o)的轉(zhuǎn)換
T convert(F value) throws IOException;
// 用于向Retrofit提供相應(yīng)Converter的工廠
abstract class Factory {
// 這里創(chuàng)建從ResponseBody其它類型的Converter,如果不能處理返回null
// 主要用于對響應(yīng)體的處理
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
// 在這里創(chuàng)建 從自定類型到ResponseBody 的Converter,不能處理就返回null碗旅,
// 主要用于對Part渡处、PartMap、Body注解的處理
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return null;
}
// 這里用于對Field祟辟、FieldMap医瘫、Header、Path旧困、Query醇份、QueryMap注解的處理
// Retrfofit對于上面的幾個(gè)注解默認(rèn)使用的是調(diào)用toString方法
public Converter<?, String> stringConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
}
}
- 5稼锅、定義Gson的Converter
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Retrofit;
public final class GsonConverterFactory extends Converter.Factory {
/**
* Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and
* decoding from JSON (when no charset is specified by a header) will use UTF-8.
*/
public static GsonConverterFactory create() {
return create(new Gson());
}
/**
* Create an instance using {@code gson} for conversion. Encoding to JSON and
* decoding from JSON (when no charset is specified by a header) will use UTF-8.
*/
public static GsonConverterFactory create(Gson gson) {
return new GsonConverterFactory(gson);
}
private final Gson gson;
private GsonConverterFactory(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
this.gson = gson;
}
//對ResponseBody進(jìn)行數(shù)據(jù)轉(zhuǎn)換的轉(zhuǎn)換器
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonResponseBodyConverter<>(gson, adapter);
}
//將未知數(shù)據(jù)轉(zhuǎn)換成RequestBody的轉(zhuǎn)換器
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonRequestBodyConverter<>(gson, adapter);
}
}
/*
//Converter.Factory中的方法
//將未知數(shù)據(jù)轉(zhuǎn)換成String類型的數(shù)據(jù)轉(zhuǎn)換器
public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
*/
三、CallAdapter
- 1僚纷、說明:
-
CallAdapter
則可以對Call
轉(zhuǎn)換矩距,這樣的話Call<T>
中的Call
也是可以被替換的。 -
addCallAdapterFactory
與addConverterFactory
同理畔濒,也有先后順序剩晴。
-
- 2、使用:
//引入RxJava2支持:
compile 'com.squareup.retrofit2:adapter-rxjava:2.6.1'
注:以上版本可能不是最新版本
//通過RxJavaCallAdapterFactory為Retrofit添加RxJava支持:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:4567/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
// 針對rxjava2.x
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
//接口設(shè)計(jì)
public interface BlogService {
@POST("/blog")
Observable<Result<List<Blog>>> getBlogs();
}
//使用:
BlogService service = retrofit.create(BlogService.class);
service.getBlogs(1)
.subscribeOn(Schedulers.io())
.subscribe(new Subscriber<Result<List<Blog>>>() {
@Override
public void onCompleted() {
System.out.println("onCompleted");
}
@Override
public void onError(Throwable e) {
System.err.println("onError");
}
@Override
public void onNext(Result<List<Blog>> blogsResult) {
System.out.println(blogsResult);
}
});
- 3侵状、CallAdapter源碼:
public interface CallAdapter<T> {
// 直正數(shù)據(jù)的類型 如Call<T> 中的 T
// 這個(gè) T 會(huì)作為Converter.Factory.responseBodyConverter 的第一個(gè)參數(shù)
// 可以參照上面的自定義Converter
Type responseType();
<R> T adapt(Call<R> call);
// 用于向Retrofit提供CallAdapter的工廠類
abstract class Factory {
// 在這個(gè)方法中判斷是否是我們支持的類型赞弥,returnType 即Call<Requestbody>和`Observable<Requestbody>`
// RxJavaCallAdapterFactory 就是判斷returnType是不是Observable<?> 類型
// 不支持時(shí)返回null
public abstract CallAdapter<?> get(Type returnType, Annotation[] annotations,
Retrofit retrofit);
// 用于獲取泛型的參數(shù) 如 Call<Requestbody> 中 Requestbody
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
// 用于獲取泛型的原始類型 如 Call<Requestbody> 中的 Call
// 上面的get方法需要使用該方法。
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}
四趣兄、相關(guān)鏈接:
Retrofit 2.0 使用教程
Retrofit2詳解
你真的會(huì)用Retrofit2嗎?Retrofit2完全教程
Retrofit2源碼解析
Retrofit之Converter簡單解析