引言
上篇中實現(xiàn)了MVP的改造,但是我們的網(wǎng)絡(luò)請求部分任然是比較冗余了谭溉,本篇將對Retrofit進行封裝墙懂。
正文
思路
對Retrofit進行封裝算是我們基礎(chǔ)框架的一部分,所以我們需要將這部分代碼封裝到 library-core 中扮念,對于封裝的實現(xiàn)思路如下:
- 將Retrofit的創(chuàng)建更改為單例模式創(chuàng)建损搬,增加可配置性,減少重復(fù)創(chuàng)建
- 將Service的創(chuàng)建也更改為單例模式
創(chuàng)建NetConfiger接口
既然是作為基礎(chǔ)框架的一部分柜与,那么在設(shè)計上面就需要高自由可配置巧勤,所以我們創(chuàng)建一個 NetConfiger 接口,用來進行 baseUrl旅挤、攔截器踢关、超時時間、debug等的配置粘茄、然后在 Application 中進行配置签舞,具體看以下代碼:
**
* 網(wǎng)絡(luò)配置器
* <p>在Application中使用</p>
*/
public interface NetConfiger {
/**
* 通用請求地址
*
* @return
*/
String configBaseUrl();
/**
* 攔截器
*
* @return
*/
Interceptor[] configInterceptors();
/**
* 連接超時時間
*
* @return
*/
long configConnectTimeoutMills();
/**
* 讀取超時時間
*
* @return
*/
long configReadTimeoutMills();
/**
* 是否調(diào)試模式
*
* @return
*/
boolean configLogEnable();
}
創(chuàng)建BaseApi
創(chuàng)建BaseApi類秕脓,主要用來做Retrofit的生成和OkhttpClient的配置等,先看代碼:
/**
* 基類 API
*/
public class BaseApi {
/**
* 網(wǎng)絡(luò)配置項
*/
private static NetConfig mConfig = null;
/**
* mRetrofit
*/
private Retrofit mRetrofit;
/**
* mClient
*/
private OkHttpClient mClient;
/**
* 默認連接超時時間
*/
private static final long DEFAULT_CONNECT_TIMEOUT_MILLS = 40 * 1000L;
/**
* 默認讀取超時時間
*/
private static final long DEFAULT_READ_TIMEOUT_MILLS = 40 * 1000L;
/**
* 實例
**/
private static BaseApi instance;
private BaseApi() {
mRetrofit = null;
mClient = null;
}
/**
* 創(chuàng)建 Retrofit
*
* @return Retrofit
*/
public static synchronized Retrofit createRetrofit() {
return getInstance().getRetrofit();
}
/**
* 單例 獲取
*
* @return BaseApi
*/
private static synchronized BaseApi getInstance() {
if (instance == null)
instance = new BaseApi();
return instance;
}
/**
* 創(chuàng)建class
*
* @param service 服務(wù)class
* @param <C> 類泛型
* @return 泛型
*/
public static <C> C get(Class<C> service) {
return getInstance().getRetrofit().create(service);
}
/**
* 注冊配置
*
* @param config
*/
public static void registerConfig(NetConfig config) {
BaseApi.mConfig = config;
//賦值為空
instance = null;
}
/**
* 獲取Retrofit
*
* @return 獲取Retrofit
*/
public Retrofit getRetrofit() {
if (mRetrofit == null) {
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(mConfig.configBaseUrl())//配置BaseUrl
.client(getHttpClient())// 設(shè)置client
.addConverterFactory(GsonConverterFactory.create());//gson轉(zhuǎn)換器
builder.addCallAdapterFactory(RxJava2CallAdapterFactory.create());
mRetrofit = builder.build();
}
return mRetrofit;
}
/**
* 獲取httpclient
*
* @return OkHttpClient
*/
private OkHttpClient getHttpClient() {
if (mClient == null) {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
// 連接超時時間
builder.connectTimeout(mConfig.configConnectTimeoutMills() != 0
? mConfig.configConnectTimeoutMills()
: DEFAULT_CONNECT_TIMEOUT_MILLS, TimeUnit.MILLISECONDS);
// 讀取超時時間
builder.readTimeout(mConfig.configReadTimeoutMills() != 0
? mConfig.configReadTimeoutMills() : DEFAULT_READ_TIMEOUT_MILLS, TimeUnit.MILLISECONDS);
// 攔截器
Interceptor[] interceptors = mConfig.configInterceptors();
if (interceptors != null && interceptors.length > 0) {
for (Interceptor interceptor : interceptors) {
builder.addInterceptor(interceptor);
}
}
if (mConfig.configLogEnable()) {//配置打印
HttpLoggingInterceptor logInterceptor = new HttpLoggingInterceptor();
logInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
builder.addInterceptor(logInterceptor);
}
mClient = builder.build();
}
return mClient;
}
}
具體方法說明如下:
registerConfig(NetConfig config)
進行網(wǎng)絡(luò)的相關(guān)配置吠架,在Application中進行調(diào)用
getHttpClient()
獲取和配置OkHttpClient
連接超時時間
讀取超時時間
自定義攔截器
請求日志攔截器
getRetrofit()
獲取Retrofit實例
配置BaseUrl
配置client
配置轉(zhuǎn)換器
其他略....
注冊相關(guān)配置
新建Application類在 AndroidManifest 中引用,并調(diào)用BaseApi的registerConfig搂鲫,傳入registerConfig的實例進行相關(guān)配置傍药,具體代碼如下:
public class DevApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
BaseApi.registerConfig(new NetConfig() {
@Override
public String configBaseUrl() {
return "http://olrt5mymy.bkt.clouddn.com/";
}
@Override
public Interceptor[] configInterceptors() {
return new Interceptor[0];
}
@Override
public long configConnectTimeoutMills() {
return 45 * 1000;
}
@Override
public long configReadTimeoutMills() {
return 45 * 1000;
}
@Override
public boolean configLogEnable() {
return true;
}
});
}
}
創(chuàng)建ServiceBuild類
在app的biz層中創(chuàng)建ServiceBuild類,主要是用來獲取service的實例魂仍。
/**
* 服務(wù)獲取類
*/
public class ServiceBuild {
/**
* 用戶服務(wù)
*/
private static UserService mUserService;
/**
* 獲取用戶服務(wù)
*/
public static synchronized UserService getUserService() {
if (null == mUserService) {
mUserService = BaseApi.createRetrofit().create(UserService.class);
}
return mUserService;
}
}
更改Presenter代碼
將LoginPresenter中創(chuàng)建Retrofit的代碼和創(chuàng)建service的代碼都去掉拐辽,換成調(diào)用ServiceBuild。
/**
* 登陸Presenter
*/
public class LoginPresenter extends LoginContract.Presenter {
private String TAG = "LoginPresenter";
public LoginPresenter(LoginContract.View view) {
super(view);
}
@Override
public void login(String userName, String password) {
// 開始請求
Subscriber subscriber = ServiceBuild.getUserService()
.login(userName, password)
.subscribeOn(Schedulers.io())//運行在io線程
.observeOn(AndroidSchedulers.mainThread())//回調(diào)在主線程
.subscribeWith(new ResourceSubscriber<LoginDto>() {
@Override
public void onNext(LoginDto loginDto) {
//結(jié)果回調(diào)
Log.e(TAG, "onNext: " + loginDto);
if (loginDto.getCode() == 200) {
view.loginSuccess(loginDto);
} else {
view.loginFailure(loginDto.getMessage());
}
}
@Override
public void onError(Throwable t) {
Log.e(TAG, "onError: ");
view.loginFailure("登陸失敳磷谩:" + t.getMessage());
}
@Override
public void onComplete() {
Log.e(TAG, "onComplete: ");
}
});
}
}
移除了大部分代碼俱诸,Presenter看上去更加的簡潔和優(yōu)雅,接下來就運行起來看看效果吧赊舶。
查看效果
運行起來看看效果吧睁搭。
效果和上章一致。
HttpLoggingInterceptor
HttpLoggingInterceptor 的作用可以說是非常的強大笼平,使用這個攔截器园骆,可以打印請求一切過程,包括請求頭寓调、請求體锌唾、請求參數(shù)、響應(yīng)頭等捶牢,對于接口對接中快速定位問題有很大的幫助鸠珠,具體看看截圖:
結(jié)束
總結(jié)
- 分離了Retrofit的創(chuàng)建,減少了代碼的冗余秋麸,利用接口來做配置項,靈活性大大提升炬太。
- 獨立了Service的創(chuàng)建灸蟆,以后直接通過ServiceBuild的get方法進行獲取。
- 雖然增加了一部分的代碼亲族,但是隨著業(yè)務(wù)的增加炒考,實則減少代碼量。
- 大多數(shù)的Service都可以放到ServiceBuild中進行創(chuàng)建霎迫,方便統(tǒng)一管理斋枢。
問題
- RxJava線程轉(zhuǎn)換還能進一步的封裝。
- RxJava沒有取消訂閱知给。
- 訂閱的時候重寫的方法過于冗余瓤帚,可以去除描姚,做統(tǒng)一的訂閱結(jié)果管理。
最后
本系列的課程還遠著呢戈次,就關(guān)于這個登陸都還能再寫兩篇文章轩勘,敬請期待。