在刚开始学Retrofit2.0+RxJava2.0时就尝试封装起来结合MVP模式使用,虽然简化了一些请求过程,但是实际使用还是有些麻烦,而且发现其中有很大的缺陷,所以就弃用了。
随着工作到现在,接触了数个实际上线项目后,趁着工作闲暇就将其总结起来,重写之前的缺陷。
Retrofit2.0+RxJava2.0的封装过程之前已经讲过,本文也是基于这个封装的,如有问题请戳:https://blog.csdn.net/DeMonliuhui/article/details/77868677
本文就是带着大家使用MVP结合着Retrofit2.0+RxJava2.0一步步封装一个简便精简的网络请求库,主要讲解MVP的架构封装过程封装。
https://github.com/DeMonLiu623/DeMon_MVPRR
Android DeMon_MVPRR的使用手册
引入如下依赖:
api 'com.squareup.okhttp3:okhttp:3.12.1'//OKHttp3.0依赖
api 'com.squareup.okhttp3:logging-interceptor:3.10.0'//OKHttp日志优化策略
api 'com.squareup.retrofit2:retrofit:2.5.0'//Retrofit2.0所需依赖
api 'io.reactivex.rxjava2:rxandroid:2.0.2'//Rxandroid2.0线程调度依赖
api 'io.reactivex.rxjava2:rxjava:2.2.5' //RxJava2.0所需依赖
api 'com.squareup.retrofit2:converter-scalars:2.5.0'//结果转为基本类型所需依赖
api 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'//RxJava2.0+Retrofit2.0适配依赖
api 'com.squareup.retrofit2:converter-gson:2.3.0'//结果转为Bean类型所需依赖
使用OKhttp封装一个优化通用的Retrofit。
public class BaseApi {
//超时时长,单位:毫秒
private int TimeOut = 7676;
public void setTimeOut(int timeOut) {
TimeOut = timeOut;
}
/**
* 使用OkHttp配置了超时及缓存策略的Retrofit
*
* @param baseUrl
* @param interceptors 自定义的拦截器
* @return
*/
public Retrofit getRetrofit(String baseUrl, Interceptor... interceptors) {
HttpLoggingInterceptor logInterceptor = new HttpLoggingInterceptor();
logInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
//缓存
File cacheFile = new File(BaseApp.getContext().getCacheDir(), "cache");
Cache cache = new Cache(cacheFile, 1024 * 1024 * 100); //100Mb
//创建一个OkHttpClient并设置超时时间
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.readTimeout(TimeOut, TimeUnit.MILLISECONDS)
.writeTimeout(TimeOut, TimeUnit.MILLISECONDS)
.connectTimeout(TimeOut, TimeUnit.MILLISECONDS)
.addInterceptor(new CacheControlInterceptor())//缓存
.addNetworkInterceptor(new CacheControlInterceptor())//网络缓存
.cache(cache);
if (BuildConfig.DEBUG) {
builder.addInterceptor(logInterceptor);//日志
}
for (Interceptor interceptor : interceptors) {
builder.addInterceptor(interceptor);
}
OkHttpClient client = builder.build();
Retrofit retrofit = new Retrofit.Builder()
.client(client)
.baseUrl(baseUrl)
.addConverterFactory(ScalarsConverterFactory.create())//请求结果转换为基本类型,一般为String
.addConverterFactory(GsonConverterFactory.create())//请求的结果转为实体类
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())//适配RxJava2.0
.build();
return retrofit;
}
}
public abstract class BaseObserver<T> implements Observer<T>, DialogHandler.CancelListener {
private static final String TAG = "BaseObserver";
private DialogHandler mDialogHandler;
private Disposable d;
private Context mContext;
private boolean isShow = true; //是否显示进度框
private ProgressDialog dialog; //进度框
public BaseObserver(Context context) {
mContext = context;
}
public BaseObserver(Context context, boolean isShow) {
mContext = context;
this.isShow = isShow;
}
@Override
public void onSubscribe(Disposable d) {
this.d = d;
showProgressDialog();
}
@Override
public void onNext(T t) {
onNextResult(t);//请求成功
}
@Override
public void onError(Throwable e) {
onErrorResult(e);//请求出错
dismissProgressDialog();
}
@Override
public void onComplete() {
dismissProgressDialog();
}
@Override
public void onCancelProgress() {
//如果处于订阅状态,则取消订阅
if (!d.isDisposed()) {
d.dispose();
}
}
protected abstract void onNextResult(T t);
protected abstract void onErrorResult(Throwable e);
/**
* 请求过程中显示的进度dialog,可重写自定义
*
* @param context
* @return
*/
public ProgressDialog initDialog(Context context) {
return new ProgressDialog(context);
}
/**
* 使用handle异步及时控制dialog的显示隐藏
*/
private void showProgressDialog() {
if (dialog == null) {
dialog = initDialog(mContext);
}
if (mDialogHandler == null) {
mDialogHandler = new DialogHandler(mContext, dialog, this);
}
if (isShow) {
mDialogHandler.obtainMessage(DialogHandler.SHOW_PROGRESS_DIALOG).sendToTarget();
}
}
private void dismissProgressDialog() {
if (mDialogHandler != null && isShow) {
mDialogHandler.obtainMessage(DialogHandler.DISMISS_PROGRESS_DIALOG).sendToTarget();
mDialogHandler = null;
}
}
}
由于Retrofit和RxJava的观察过程已经封装好,所以我们在Model中只需要简单做一些线程管理,和订阅管理即可。
将请求和取消放在子线程中,将结果返回到主线程,进行统一管理。
public class BaseModel {
protected final String TAG = this.getClass().getSimpleName();
public static Context mContext;
protected <T> void addSubcription(Observable<T> ob, Observer<T> callback) {
if (callback != null && ob != null) {
ob.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(callback);
}
}
}
封装Presenter层解决Presenter与View层的数据交互问题。
/**
*让所有View接口必须实现,这个接口可以什么都不做,只是用于约束类型
*/
public interface BaseView {
}
/**
* Presenter层接口,约束类型。
* 因为BasePresenter通过泛型与View接口绑定,在kotlin中调用会有泛型型变的转换问题
* 所以该接口主要是为了解决kotlin调用的泛型型变问题
*/
public interface BasePresenterInfc {
void setContext(Context context);
void onStart(BaseView view);
void onDestroy();
}
public class BasePresenter<V extends BaseView> implements BasePresenterInfc {
protected final String TAG = this.getClass().getSimpleName();
protected V mView;
protected Context mContext;
/**
* 获取V层
*/
public V getView() {
return mView;
}
@Override
public void setContext(Context context) {
mContext = context;
}
/**
* 绑定V层
*
* @param view V层
*/
@Override
public void onStart(BaseView view) {
mView = (V) view;
}
/**
* 解绑V层
*/
@Override
public void onDestroy() {
mView = null;
}
}
public abstract class BaseMvpActivity<T extends BasePresenterInfc> extends AppCompatActivity implements BaseView {
protected final String TAG = this.getClass().getSimpleName();
public Context mContext;
protected T mPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
BaseModel.mContext = this;
mContext = this;
initParam(getIntent());
initLayout();
initPresenter();
initCreate();
}
/**
* 初始化布局
* 封装成方法的目的:
* 例如需要实现含有标题栏的BaseActivity可重写此方法
*/
protected void initLayout() {
setContentView(bindLayout());
}
/**
* 获取绑定的布局
*/
protected abstract int bindLayout();
/**
* 获取泛型实例化Presenter
* 绑定View
*/
private void initPresenter() {
mPresenter = TUtil.getT(this);
if (mPresenter!=null){
mPresenter.setContext(mContext);
mPresenter.onStart(this);
}
}
protected void initParam(Intent intent) {
}
protected abstract void initCreate();
/**
* 解绑View
*/
@Override
protected void onDestroy() {
super.onDestroy();
if (mPresenter!=null){
mPresenter.onDestroy();
}
}
}
public class TUtil {
public static <T> T getT(Object o) {
try {
return ((Class<T>) ((ParameterizedType) (o.getClass()
.getGenericSuperclass())).getActualTypeArguments()[0]).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}