官網:https://square.github.io/retrofit/
簡介:
示例:
- 集成
//build.gradle 引入
implementation 'com.squareup.retrofit2:retrofit:(insert latest version)'
//AndroidManifest.xml 中添加權限
<uses-permission android:name="android.permission.INTERNET"/>
- 使用
//① 創建Java接口
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
//② Retrofit實現創建的Java接口
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create()) // 設置數據解析器
.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 支持RxJava平臺
.build();
GitHubService service = retrofit.create(GitHubService.class);
//③調用(同步或異步選其一)
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組合規則
Retrofit2
的baseUlr
必須以/
(斜線) 結束,不然會拋出一個IllegalArgumentException
。
所以如果看到別的教程沒有以/
結束,那么多半是直接從Retrofit 1.X
照搬過來的。
一、Retrofit注解
Retrofit注解
1、@HTTP
- 有三個屬性:
method
、path
、hasBody
/**
* method 表示請求的方法,區分大小寫
* path表示路徑
* hasBody表示是否有請求體
*/
@HTTP(method = "GET", path = "blog/{id}", hasBody = false)
Call<ResponseBody> getBlog(@Path("id") int id);
-
注:
method
的值retrofit
不會做處理,所以要自行保證其準確性,
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()
說明:
以上的效果是一致的。
- 區別在于使用場景和使用方式
- 使用場景:@Header用于添加不固定的請求頭,@Headers用于添加固定的請求頭
- 使用方式:@Header作用于方法的參數;@Headers作用于方法
4、@Body
-
@Body
的參數如果是一個Map
,則作用相當于@Field
不過Map要經過 FormBody.Builder 類處理成為符合 Okhttp 格式的表單,如:
FormBody.Builder builder = new FormBody.Builder();
builder.add("key","value");
5、@Field & @FieldMap;@Part & @PartMap
-
@Field
與@FieldMap
配合使用,在發送Post
請求時提交請求的表單字段 -
@Part
與@Field
的區別:功能相同,但攜帶的參數類型更加豐富,包括數據流,所以適用于 有文件上傳 的場景
6、@Query和@QueryMap
- 用于 @GET 方法的查詢參數(Query 相當于 Url 中 ‘?’ 后面的 key-value)
二、Converter
-
1、Retrofit支持多種數據解析方式
解析器
注:以上版本可能不是最新版本 -
2、說明:
-
Convert.Factoy
的具體作用就是獲取一個Convert
-
Converter
是對于Call<T>
中T
的轉換 -
addConverterFactory
是有先后順序的,如果有多個ConverterFactory
都支持同一種類型,那么就是只有第一個才會被使用,而GsonConverterFactory
是不判斷是否支持的,所以這里交換了順序還會有一個異常拋出,原因是類型不匹配。
-
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> {
// 實現從 F(rom) 到 T(o)的轉換
T convert(F value) throws IOException;
// 用于向Retrofit提供相應Converter的工廠
abstract class Factory {
// 這里創建從ResponseBody其它類型的Converter,如果不能處理返回null
// 主要用于對響應體的處理
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
// 在這里創建 從自定類型到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對于上面的幾個注解默認使用的是調用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進行數據轉換的轉換器
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonResponseBodyConverter<>(gson, adapter);
}
//將未知數據轉換成RequestBody的轉換器
@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中的方法
//將未知數據轉換成String類型的數據轉換器
public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
*/
三、CallAdapter
- 1、說明:
-
CallAdapter
則可以對Call
轉換,這樣的話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();
//接口設計
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> {
// 直正數據的類型 如Call<T> 中的 T
// 這個 T 會作為Converter.Factory.responseBodyConverter 的第一個參數
// 可以參照上面的自定義Converter
Type responseType();
<R> T adapt(Call<R> call);
// 用于向Retrofit提供CallAdapter的工廠類
abstract class Factory {
// 在這個方法中判斷是否是我們支持的類型,returnType 即Call<Requestbody>和`Observable<Requestbody>`
// RxJavaCallAdapterFactory 就是判斷returnType是不是Observable<?> 類型
// 不支持時返回null
public abstract CallAdapter<?> get(Type returnType, Annotation[] annotations,
Retrofit retrofit);
// 用于獲取泛型的參數 如 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);
}
}
}
四、相關鏈接:
Retrofit 2.0 使用教程
Retrofit2詳解
你真的會用Retrofit2嗎?Retrofit2完全教程
Retrofit2源碼解析
Retrofit之Converter簡單解析