這個(gè)框架在項(xiàng)目的使用中已經(jīng)有好一段時(shí)間了济锄,于是把其中基本的模塊抽取出來寫出來。
demo結(jié)構(gòu)圖:
搭建流程:
引入所需依賴庫:
//Rxjava
implementation 'io.reactivex:rxjava:1.1.0'
implementation 'io.reactivex:rxandroid:1.1.0'
//Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
implementation 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
implementation 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'
//Gson
implementation 'com.google.code.gson:gson:2.6.2'
使用Retrofit+Rxjava
1.請(qǐng)求接口地址以及聲明類:
功能是初始化retrofit和okhttp;設(shè)置okhttp的header攔截器踩娘、請(qǐng)求數(shù)據(jù)攔截器熙尉、請(qǐng)求緩存攔截器。
public interface ApiService {
/** 正式服務(wù)器地址 */
String SERVER_ADDRESS_RELEASE = "";
/** 測(cè)試服務(wù)器地址 */
String SERVER_ADDRESS_DEBUG = "";
/** 服務(wù)器域名 */
String SERVER_ADDRESS = isDebug ? SERVER_ADDRESS_DEBUG : SERVER_ADDRESS_RELEASE;
@GET("")
Observable<BaseModel<VideoBean>> getVideoData();
}
2.單例的Retrofit和Okhttp管理類
單例模式創(chuàng)建ApiService類窗轩,添加服務(wù)器地址,設(shè)置5秒請(qǐng)求超時(shí)座咆。ApiService默認(rèn)返回Call類型痢艺,但是需要直接轉(zhuǎn)化Observable類型,此時(shí)需要添加addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 介陶。需要直接轉(zhuǎn)化為需要的實(shí)體類堤舒,需要添加addCallAdapterFactory(RxJavaCallAdapterFactory.create())
public class ApiManager {
private static ApiManager mApiManager;
private OkHttpClient mOkHttpClient;
private static ApiService mApiService;
private final int TIMEOUT = 10;
private ApiManager() {
initOkhttp();
initRetrofit();
}
public static synchronized ApiService getApiService() {
if (mApiService == null) {
mApiManager = new ApiManager();
}
return mApiService;
}
private void initOkhttp() {
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.connectTimeout(TIMEOUT, TimeUnit.SECONDS) //連接超時(shí)設(shè)置
.readTimeout(TIMEOUT, TimeUnit.SECONDS) //寫入緩存超時(shí)10s
.writeTimeout(TIMEOUT, TimeUnit.SECONDS) //讀取緩存超時(shí)10s
.retryOnConnectionFailure(true) //失敗重連
.addInterceptor(new HeaderInterceptor()) //添加header
.addInterceptor(new NetCacheInterceptor()); //添加網(wǎng)絡(luò)緩存
addLogIntercepter(builder); //日志攔截器
setCacheFile(builder); //網(wǎng)絡(luò)緩存
mOkHttpClient = builder.build();
}
private void initRetrofit() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(ApiService.SERVER_ADDRESS)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.client(mOkHttpClient)
.build();
mApiService = retrofit.create(ApiService.class);
}
/**
* 設(shè)置緩存文件路徑
*/
private void setCacheFile(OkHttpClient.Builder builder) {
//設(shè)置緩存文件
File cacheFile = new File(DirConfig.HTTP_CACHE);
//緩存大小為10M
int cacheSize = 10 * 1024 * 1024;
Cache cache = new Cache(cacheFile,cacheSize);
builder.cache(cache);
}
/**
* 調(diào)試模式下加入日志攔截器
* @param builder
*/
private void addLogIntercepter(OkHttpClient.Builder builder) {
if (AppConfig.isDebug) {
builder.addInterceptor(new LoggingInterceptor());
}
}
}
3.給okhttp添加攔截器
- 統(tǒng)一添加header的攔截器:
public class HeaderInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request.Builder builder = chain.request().newBuilder();
builder.addHeader("token", UserInfoCache.TOKEN);
return chain.proceed(builder.build());
}
}
- Okhttp返回?cái)?shù)據(jù)日志攔截器:
public class LoggingInterceptor implements Interceptor {
private final int byteCount = 1024*1024;
@Override
public Response intercept(Chain chain) throws IOException {
//chain里面包含了request和response,按需獲取
Request request = chain.request();
Response response = chain.proceed(request);
LogUtils.d(String.format("發(fā)送請(qǐng)求 %s",request.url()));
ResponseBody responseBody = response.peekBody(byteCount);
LogUtils.d(String.format("接收響應(yīng) %s", responseBody.string()));
return response;
}
}
- 網(wǎng)絡(luò)攔截器進(jìn)行網(wǎng)絡(luò)緩存:
public class NetCacheInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
int onlineCacheTime = 60;
return response.newBuilder()
.header("Cache-Control", "public, max-age="+onlineCacheTime)
.removeHeader("Pragma")
.build();
}
}
4.自定義請(qǐng)求數(shù)據(jù)回調(diào)和過濾:
封裝泛型實(shí)體類的觀察者哺呜,統(tǒng)一處理結(jié)果舌缤。請(qǐng)求成功給下一層返回實(shí)體類。請(qǐng)求失敗從HttpException中獲取code設(shè)置對(duì)應(yīng)的errorMsg
public abstract class ApiCallBack<M extends BaseModel> extends Subscriber<M> {
@Override
public void onCompleted() { }
@Override
public void onError(Throwable e) {
e.printStackTrace();
if (e instanceof HttpException) {
HttpException httpException = (HttpException) e;
int code = httpException.code();
//Http狀態(tài)碼提示
if (code >=400 && code< 500) {
LogUtils.e("請(qǐng)求錯(cuò)誤");
} else if (code >= 500) {
LogUtils.e("服務(wù)器錯(cuò)誤");
}
}
}
@Override
public void onNext(M baseModel) {
handleStatusCode(baseModel);
}
/**
* 后臺(tái)statuscode狀態(tài)碼處理弦牡,狀態(tài)碼類型封裝在StatusCodeEnum中
* @param baseModel
*/
private void handleStatusCode(M baseModel) {
String statusCode = baseModel.code;
StatusCodeEnum statusCodeEnum = StatusCodeEnum.getByCode(statusCode);
switch (statusCodeEnum) {
case RESULT_OK: //請(qǐng)求成功
onSuccess(baseModel);
break;
case RESULT_TOKENINVALID: //token失效
// TODO: 2018/11/23 token失效友驮,刪除本地用戶信息儲(chǔ)存并退出登錄
break;
default:
LogUtils.e("請(qǐng)求失敗錯(cuò)誤");
break;
}
}
/**
* onSuccess回調(diào)的數(shù)據(jù)為程序具體需要的業(yè)務(wù)狀態(tài)碼,具體數(shù)據(jù)等
*/
public abstract void onSuccess(M m);
}
MVP加入:
1.View
Iview類:規(guī)定所有Activity,fragment等容器的公共行為驾锰,例如顯示加載框和隱藏
public interface IView {
void showLoading();
void hideLoading();
}
IBaseView:
public interface IBaseView<M extends BaseModel> extends IView {
}
2.presenter
Ipresenter:
public interface Ipresenter<V extends IView> {
/**
* 關(guān)聯(lián)P與V
* @param v
*/
void attachView(V v);
/**
* 取消關(guān)聯(lián)P與V
*/
void detachView();
/**
* Rx訂閱
*/
void subscribe(Observable observable, Subscriber subscriber);
/**
* Rx取消訂閱
*/
void unSubscribe();
}
BasePresenter:
Basepresenter,抽象的persenter業(yè)務(wù)處理層卸留。關(guān)聯(lián)抽象層view和抽象model,通過CompositeSubscription關(guān)聯(lián)數(shù)據(jù)請(qǐng)求椭豫,并通過subscriber回調(diào)回view層耻瑟。
public class BasePresenter<V extends IBaseView> implements Ipresenter<V> {
protected V view;
protected ApiService apiService;
protected CompositeSubscription mCompositeSubscription;
@Override
public void attachView(IBaseView v) {
this.view = (V) v;
apiService = ApiManager.getApiService();
}
@Override
public void detachView() {
this.view = null;
unSubscribe();
}
@Override
public void subscribe(Observable observable, Subscriber subscriber) {
if (mCompositeSubscription == null) {
mCompositeSubscription = new CompositeSubscription();
}
//綁定observable與subscriber
Subscription subscription = observable.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(subscriber);
mCompositeSubscription.add(subscription);
}
@Override
public void unSubscribe() {
if (mCompositeSubscription != null && mCompositeSubscription.hasSubscriptions()) {
mCompositeSubscription.unsubscribe();
}
}
}
3.Model
BaseModel:請(qǐng)求數(shù)據(jù)實(shí)體類基類旨指,對(duì)需要的data數(shù)據(jù)進(jìn)行泛型處理
public class BaseModel<T> implements IModel,Serializable {
/** 自定義錯(cuò)誤碼 */
public String code;
/** 自定義業(yè)務(wù)狀態(tài)碼 */
public String bizcode;
/** 消息提示 */
public String msg;
/** 泛型實(shí)體類 */
public T data;
public boolean isOk() {
return bizcode.equals(AppConfig.BIZCODE_OK);
}
}
4.MvpActivity基類:
MvpActivity綁定presenter,在銷毀時(shí)解綁喳整,調(diào)用onUnsubscribe()將rxjava統(tǒng)一取消注冊(cè)谆构,以避免內(nèi)存泄露。至于BaseActivity功能根據(jù)項(xiàng)目業(yè)務(wù)需求進(jìn)行封裝框都。比如跳轉(zhuǎn)搬素,加載彈出框,是否全屏魏保,頻繁調(diào)用工具類等熬尺。
public abstract class BaseMvpActivity<P extends BasePresenter> extends AppCompatActivity {
protected P mPresenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
mPresenter = createPresenter();
super.onCreate(savedInstanceState);
}
protected abstract P createPresenter();
@Override
protected void onDestroy() {
super.onDestroy();
//頁面銷毀時(shí)取消presenter綁定
if (mPresenter != null) {
mPresenter.detachView();
}
}
}
實(shí)現(xiàn)MainActivity的功能:
1.MainView:
public interface MainView extends IBaseView {
void getVideoData(BaseModel<VideoBean> videoBeanBaseModel);
}
2.MainPresenter:
public class MainPresenter extends BasePresenter<MainView> {
public MainPresenter(MainView mainView) {
attachView(mainView);
}
public void getVideoData() {
view.showLoading();
subscribe(apiService.getVideoData(), new ApiCallBack<BaseModel<VideoBean>>() {
@Override
public void onSuccess(BaseModel<VideoBean> videoBeanBaseModel) {
view.hideLoading();
view.getVideoData(videoBeanBaseModel);
}
});
}
}
2.MainActivity:
public class MainActivity extends BaseMvpActivity<MainPresenter> implements MainView{
private TextView tvContent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvContent = findViewById(R.id.tv_content);
mPresenter.getVideoData();
}
@Override
protected MainPresenter createPresenter() {
return new MainPresenter(this);
}
@Override
public void showLoading() {
}
@Override
public void hideLoading() {
}
@Override
public void getVideoData(BaseModel<VideoBean> videoBeanBaseModel) {
tvContent.setText(videoBeanBaseModel.data.toString());
}
}
好的,打完收工谓罗。