在开发阶段,如果有一个好的开发框架,不仅能提高开发效率,更能减少后期维护的时间。结合自己的实际,封装了一套MVP+RxJava+Retrofit2+Okhttp3+Rxlifecycle+Butterknife的开发框架。架构层:V层只负责视图的操作,P层只负责数据的交互,M层负责逻辑的处理,应该属于完整意义上的MVP代码结构模式。网络层包括:普通的get/post请求,文件上传、文件带进度下载,无网络缓存策略,请求带加载的dialog等。
先直接上代码链接:
GitHub: https://github.com/634930172/JohnDevFrame
CSDN: https://download.csdn.net/download/a634930172a/10489294
本项添加的依赖如下:
//Network implementation 'com.squareup.retrofit2:retrofit:2.3.0' implementation 'com.google.code.gson:gson:2.8.5' implementation 'com.squareup.retrofit2:adapter-rxjava:2.3.0' //RxJava implementation 'io.reactivex:rxandroid:1.2.1' implementation 'io.reactivex:rxjava:1.3.0' //RxLifecycle implementation 'com.trello:rxlifecycle:0.3.0' implementation 'com.trello:rxlifecycle-components:0.3.0' //ButterKnife implementation 'com.jakewharton:butterknife:8.8.1' annotationProcessor'com.jakewharton:butterknife-compiler:8.8.1'
MVP模式设计
MVP模式大家应该都有了解过,V层想要得到某个数据然后做视图操作,需通过P层向M层发送请求,M层处理后的结果回调给P层,P层再回调给V层,期间的传递过程都是通过接口访问的。
本项目的结构如下所示:
下面看看封装MVP的思路吧。
首先是对Base各个基类的封装。BaseAct如下所示:
public abstract class BaseAct<V,P extends BasePresenter<V>> extends RxAppCompatActivity {
public Activity mActivity;
public P mPresenter;
@Override
public void setContentView(@LayoutRes int layoutResID) {
super.setContentView(layoutResID);
ButterKnife.bind(this);
mActivity = this;
}
@Override
public void setContentView(View view) {
super.setContentView(view);
ButterKnife.bind(this);
mActivity = this;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPresenter = createPresenter();
mPresenter.attachView((V) this);
setContentView(getLayoutId());
initView();
initData();
initEvent();
}
protected abstract int getLayoutId();
protected abstract P createPresenter();
/**
* 初始化View
*/
protected void initView() {
}
/**
* 初始化数据
*/
protected void initData() {
}
/**
* 初始化事件
*/
protected void initEvent() {
}
@Override
protected void onDestroy() {
if (mPresenter != null) {
mPresenter.detachView();
}
super.onDestroy();
}
}
其中V为View的泛型,P为Presenter的泛型,RxAppCompatActivity是Rxlifecycle包下的,如下所示。该类继承了AppCompatActivity,增加了bindUntilEvent()和bindtoLifecycle()等方法,配合网络请求绑定生命周期的方法,可以避免内存泄漏。mPresenter通过调用attachView()和detachView()实现手动绑定和解绑,也起到了防止内存泄漏的作用。
public class RxAppCompatActivity extends AppCompatActivity implements ActivityLifecycleProvider { private final BehaviorSubject<ActivityEvent> lifecycleSubject = BehaviorSubject.create(); @Override public final Observable<ActivityEvent> lifecycle() { return lifecycleSubject.asObservable(); } @Override public final <T> Observable.Transformer<T, T> bindUntilEvent(ActivityEvent event) { return RxLifecycle.bindUntilActivityEvent(lifecycleSubject, event); } @Override public final <T> Observable.Transformer<T, T> bindToLifecycle() { return RxLifecycle.bindActivity(lifecycleSubject); }
BasePresenter如下所示:
public abstract class BasePresenter<V> implements Presenter<V> { protected WeakReference<V> mMvpView; @Override public void attachView(V mvpView) { this.mMvpView = new WeakReference<>(mvpView); } protected V getView() { return mMvpView.get(); } @Override public void detachView() { if (mMvpView != null) { mMvpView.clear(); mMvpView = null; } }
BasePresenter将BaseAct绑定的View视图包装成弱引用,防止了内存泄漏(三重保障,稳稳的不泄漏)。Presenter是一个提供方法的接口,如下:
public interface Presenter<V> { void attachView(V view); void detachView(); }
BaseModule如下所示:
public class BaseModule { protected BaseAct mActivity; protected BaseFrag mFragment; public BaseModule(BaseAct act){ this.mActivity=act; } public BaseModule(BaseFrag frag){ this.mFragment=frag; } protected <T> void addActSubscribe(Observable<T> observable,Subscriber<T> subscriber ) { observable.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .compose(mActivity.<T>bindUntilEvent(ActivityEvent.DESTROY))//绑定生命周期,防止内存泄露 .subscribe(subscriber); } protected <T> void addFragSubscribe(Observable<T> observable,Subscriber<T> subscriber ) { observable.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .compose(mFragment.<T>bindUntilEvent(FragmentEvent.DESTROY))//绑定生命周期,防止内存泄露 .subscribe(subscriber); } }
里面将原始的网络请求方法抽了出来,并持有Act或者Frag的对象。只要子类继承了BaseModule,就可以在Module层为所欲为处理自己想要的逻辑了。
下面是具体的MainAct,MainPresenter,MainModelImp,如下所示:
public class MainAct extends BaseAct<MainView, MainPresenter> implements MainView { @BindView(R.id.bt) Button bt; @BindView(R.id.bt2) Button bt2; @BindView(R.id.bt3) Button bt3; @BindView(R.id.bt4) Button bt4; @BindView(R.id.bt5) Button bt5; @BindView(R.id.bt6) Button bt6; @BindView(R.id.tv) TextView tv; @Override protected int getLayoutId() { return R.layout.activity_main; } @Override protected MainPresenter createPresenter() { return new MainPresenter(this); } /** * 点击事件 业务请求 */ @OnClick({R.id.bt, R.id.bt2, R.id.bt3, R.id.bt4, R.id.bt5, R.id.bt6}) public void onClick(View view) { switch (view.getId()) { case R.id.bt://get请求 mPresenter.SimpleGet(); break; case R.id.bt2://post请求 mPresenter.SimplePost(); break; case R.id.bt3://单图上传 mPresenter.fileUpload(); break; case R.id.bt4://多图上传 mPresenter.fileUploads(); break; case R.id.bt5://文件带进度下载 mPresenter.fileDownLoad(); break; case R.id.bt6://无网络取缓存,测试时将网络关闭 mPresenter.simpleGetCache(); break; } } //------------------------------业务回调--------------------------- /** * get请求回调 */ @Override public void simpleGetCallback(String str) { tv.setText(String.valueOf("get成功请求返回数据: " + str)); } /** * Post请求回调 */ @Override public void simplePostCallback(JsonObject jsonObject) { tv.setText(Stri