對(duì)于Retrofit的使用我就不介紹了,使用也不難,隨便去搜兩篇文章看看。
我主要介紹的就是如何封裝,簡(jiǎn)便使用。
數(shù)據(jù)的封裝可以移步到:Retrofit網(wǎng)絡(luò)請(qǐng)求,數(shù)據(jù)的封裝(一)
一、Retrofit工具類的封裝(核心類)
/**
* Retrofit工具類
*/
public class RetrofitUtils {
public static final String BASE_URL = "http://XXX";
/**
* 超時(shí)時(shí)間
*/
public static final int TIMEOUT = 60;
private static volatile RetrofitUtils mInstance;
private Retrofit mRetrofit;
public static RetrofitUtils getInstance() {
if (mInstance == null) {
synchronized (RetrofitUtils.class) {
if (mInstance == null) {
mInstance = new RetrofitUtils();
}
}
}
return mInstance;
}
private RetrofitUtils() {
initRetrofit();
}
/**
* 初始化Retrofit
*/
private void initRetrofit() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
// 設(shè)置超時(shí)
builder.connectTimeout(TIMEOUT, TimeUnit.SECONDS);
builder.readTimeout(TIMEOUT, TimeUnit.SECONDS);
builder.writeTimeout(TIMEOUT, TimeUnit.SECONDS);
OkHttpClient client = builder.build();
mRetrofit = new Retrofit.Builder()
// 設(shè)置請(qǐng)求的域名
.baseUrl(BASE_URL)
// 設(shè)置解析轉(zhuǎn)換工廠,用自己定義的
.addConverterFactory(ResponseConvert.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(client)
.build();
}
/**
* 創(chuàng)建API
*/
public <T> T create(Class<T> clazz) {
return mRetrofit.create(clazz);
}
}
代碼很簡(jiǎn)單,創(chuàng)建后臺(tái)請(qǐng)求接口,調(diào)用create即可。
二、Converter.Factory的封裝
自己采用Gson封裝解析。
/**
* 自定義Gson解析轉(zhuǎn)換
*/
public class ResponseConvert extends Converter.Factory {
public static ResponseConvert create() {
return new ResponseConvert();
}
/**
* 轉(zhuǎn)換的方法
*/
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
return new BodyConverter<>(type);
}
private class BodyConverter<T> implements Converter<ResponseBody, T> {
private Gson gson;
private Type type;
public BodyConverter(Type type) {
this.type = type;
gson = new GsonBuilder()
.registerTypeHierarchyAdapter(List.class, new ListTypeAdapter())
.create();
}
@Override
public T convert(ResponseBody value) throws IOException {
String json = value.string();
return gson.fromJson(json, type);
}
}
/**
* 空列表的轉(zhuǎn)換
*/
private static class ListTypeAdapter implements JsonDeserializer<List<?>> {
@Override
public List<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (json != null && json.isJsonArray()) {
JsonArray array = json.getAsJsonArray();
Type itemType = ((ParameterizedType) typeOfT).getActualTypeArguments()[0];
java.util.List list = new ArrayList<>();
for (int i = 0; i < array.size(); i++) {
JsonElement element = array.get(i);
Object item = context.deserialize(element, itemType);
list.add(item);
}
return list;
} else {
//和接口類型不符,返回空List
return Collections.EMPTY_LIST;
}
}
}
}
三、Retrofit網(wǎng)絡(luò)請(qǐng)求基類的封裝
/**
* 后臺(tái)統(tǒng)一接口API
*/
public interface ServerApi {
// 聯(lián)系人編輯
@POST(URLS.LOGIN)
Observable<ResponseBean<LoginBean>> login(@Body RequestBody requestBody);
}
/**
* 請(qǐng)求網(wǎng)絡(luò)業(yè)務(wù)的基類,AppPresenterr 的封裝
*/
public class AppPresenter {
protected ServerApi mApi = RetrofitUtils.getInstance().create(ServerApi.class);
private static final Gson gson = new Gson();
/**
* 1. 轉(zhuǎn)換
* 統(tǒng)一處理一些動(dòng)作
*/
public static <T> void convert(Observable<ResponseBean<T>> observable, Observer<T> observer) {
observable
.map(new Function<ResponseBean<T>, T>() {
@Override
public T apply(ResponseBean<T> httpResult) throws Exception {
// 打印響應(yīng)的對(duì)象
LogUtils.object(httpResult);
// TODO 實(shí)際開(kāi)發(fā)的時(shí)候統(tǒng)一處理一些東西
if (httpResult == null || httpResult.head == null) {
throw new RuntimeException("請(qǐng)求數(shù)據(jù)異常");
} else if (!"1".equals(httpResult.head.bcode)) {
throw new RuntimeException(httpResult.head.bmessage);
}
return httpResult.data;
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer);
}
/**
* 2. 執(zhí)行的方法
*/
public static <T> void execute(Observable<ResponseBean<T>> observable, Observer<ResponseBean<T>> observer) {
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer);
}
/**
* 3.請(qǐng)求數(shù)據(jù)是Json,Json轉(zhuǎn)成RequestBody
*/
public static RequestBody createRequestBody(Object obj) {
RequestBean bean = new RequestBean<>(obj);
String json = gson.toJson(bean);
// 打印請(qǐng)求的Json
LogUtils.json(json);
RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
return body;
}
}
有三個(gè)通用的方法:
1.convert方法,轉(zhuǎn)換、統(tǒng)一處理網(wǎng)絡(luò)請(qǐng)求,將公共處理部分放在這方法里面。
2.execute方法,只執(zhí)行,不做任何處理操作,適用于一些不能統(tǒng)一處理的接口。
3.createRequestBody方法,就是統(tǒng)一創(chuàng)建請(qǐng)求的RequestBody。
如有些代碼看不懂,請(qǐng)看:
Retrofit網(wǎng)絡(luò)請(qǐng)求,數(shù)據(jù)的封裝(一)
四、具體網(wǎng)絡(luò)請(qǐng)求業(yè)務(wù)類
/**
* 登錄的業(yè)務(wù)類
*/
public class LoginPresenter extends AppPresenter {
/**
* 登錄的接口
*/
public void login(LoginData data, Observer<LoginBean> observer) {
Observable<ResponseBean<LoginBean>> login = mApi.login(createRequestBody(data));
// 轉(zhuǎn)換
convert(login, observer);
}
}
五、測(cè)試和使用
/**
* 調(diào)用登錄接口
*/
public void open(View view) {
LoginData loginData = new LoginData("135****5219", "12***56");
presenter.login(loginData, new DialogObserver<LoginBean>(getAppActivity()) {
@Override
public void onNext(LoginBean data) {
// TODO 做登錄的成功的操作
Toast.makeText(getAppActivity(), "" + data.userInfo.nickName, Toast.LENGTH_SHORT).show();
}
});
}
六、補(bǔ)充,對(duì)于Observer<T>需要再次封裝。
1.如調(diào)用登錄要顯示Dialog
2.如Activity銷毀要取消請(qǐng)求。
3.結(jié)合加載數(shù)據(jù)各種狀態(tài)頁(yè)面,如:加載中、加載失敗、網(wǎng)絡(luò)異常、數(shù)據(jù)為空等等
這些都是可以統(tǒng)一封裝在Observer<T>里面。