Android应用MVP实践——MingMVP
前言
在Android应用开发领域有三种开发模式MVC,MVP和MVVM。三种开发架构各有各的优势。都是为了分离视图层和业务逻辑层解决它们之间的耦合。本文记根据自己对MVP的理解实现Android MVP开发模式的实现——MingMVP。本文针对已对MVP开发模式有所了解的同学。对MVP开发模式还不是很了解的同学可以参考以下文章:
Android MVP 详解(上)
Android MVP 详解(下)
传统的MVP模式
大多数人在了解MVP开发模式之后也会写出简单的MVP实现。简单的MVP模式如下:
#BaseView
public interface BaseView{
//空
}
#BasePresenter
public interface BasePresenter{
void start();
void destroy();
//空
}
#MainContract
public interface MainContract{
interface View extends BaseView{
Context getContext();
//View层要实现的接口
}
interface Presenter extends BasePresenter{
//Presenter层要实现的接口
}
}
#MainActivity
public class MainActivity implements MainContract.View{
private MainPresenter mPresenter;
public void onCreate(Bundle saved..){
super.onCreate(saved...);
setContentView(...);
mPresenter = new MainPresenter(this);
...
mPresenter.start();
...
}
public void onDestroy(){
super.onDestroy();
mPresenter.destory();
}
public Context getContext(){
return 上下文实例。
}
}
#MainPresenter
public class MainPresenter implements MainContract.Presenter{
private MainContract.View mView;
public MainPresenter(MainContract.View view){
this.mView = view;
}
public void start(){
//业务初始化代码
}
public void destroy(){
//业务结束代码
}
.....具体接口实现
}
上面代码就是简单的一个MVP模式的实现。上面的代码特点是简洁。但是我们发现在我们要执行Presenter层的代码时都需要View层调用一下Presenter的方法,也就是View层驱动Presenter层执行具体业务逻辑。现在能不能每次写MVP模式的界面,View层不需要显式调用Presenter的启动方法。让Presenter层拥有View层一样的生命周期呢?MingMVP就是为了让开发者从每次写MVP模式界面都要让View层调用一下Presenter层的初始化代码解放,让Presenter层拥有View层相同的生命周期,让Presenter当家做主(当然也是假的当家作主,只不过在用MingMVP这框架的开发者开来确实是”当家作主”)。
注:由于Model层的写法每个人、公司都有所不同,为了让MingMVP通用,不考虑Model的写法,当然也不要在View层出现Model层相关的逻辑。
MingMVP
MingMVP的使用
在讲解MingMVP如何实现之前,大概讲一下MingMVP的使用,让读者们了解Presenter层是如何“当家作主”的。
1.创建UI交互接口
public interface MainContract {
interface View extends IView{
void operationView1();
void operationView2();
}
interface Presenter extends IPresenter{
void operation1();
}
}
2.创建Presenter层类,继承BasePresenter并实现具体Presenter接口
public class MainPresenter extends BasePresenter<MainContract.View> implements MainContract.Presenter {
public MainPresenter(Context ctx, MainContract.View v) {
super(ctx, v);
}
@Override
public void operation1() {
...
mView.operationView1();
...
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
...相当于Activity的onCreate生命期
}
//还有onResume、onStart等等Activity相似的生命周期,除了onCreate方法,其他生命周期 的实现不是必须的。
}
3.创建View层继承BaseMVPActivity/BaseMVPFragment/BaseMVPDialog并实现View接口
public class MainActivity extends BaseMVPActivity<MainContract.Presenter> implements MainContract.View {
Button btn_load;
TextView tv_data;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
protected MainContract.Presenter createPresenter() {
return new MainPresenter(this, this);
}
@Override
protected void bindViews() {
btn_load = findView(R.id.btn_main_load);
tv_data = findView(R.id.tv_main_data);
btn_load.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPresenter.operation1();
}
});
}
@Override
public int getLayoutID() {
return R.layout.activity_main;
}
@Override
public void operationView1() {
tv_data.setText("点击按钮");
}
@Override
public void operationView2() {
tv_data.setText("Presenter onCreate");
}
}
在上面可以看到,在Presenter层也有Activity一样的onCreate,View层除了createPresenter中创造了Presenter后,View层和Presenter层的地位平等了。Presenter有了和Activity一样的生命周期,能决定自己在什么时候干什么事。在生命周期内View层和Presenter层都能平等的调用相互之间开放的接口,而无须View层驱动。当然交互操作还是需要View层通知Presenter层执行相应的业务逻辑代码。
MingMVP的实现原理
MingMVP的实现只有7个文件。
以下是对每个java文件的说明:
IView:作为View层的一个标识接口。
IPresenter:作为Presenter层的一个标识接口。
IMVPView:View层都需要实现的接口。
BasePresenter:Presenter层的基类,只包含Presenter生命周期方法和View层的引用。
BaseMVPActivity/Dialog/Fragment:View层的基类。
由于IView和IPresenter只作为标识接口,这里就不贴出其代码。
IMVPView
public interface IMVPView {
/**
* Specify layout id for the view content.
*/
@LayoutRes int getLayoutID();
}
这个接口需要View层实现,这里只有一个方法getLayoutID,主要用于返回View层的layout文件。
BasePresenter
/**
* Base class of Presenter.
* Created by luozm on 2017/7/19.
*/
public abstract class BasePresenter<T extends IView> {
private Context mContext;
private T mView;
public BasePresenter(Context ctx, T v) {
this.mContext = ctx;
this.mView = v;
}
public abstract void onCreate(@Nullable Bundle savedInstanceState);
//销毁View层引用以免循环引用导致View层类的内存泄漏,当然也可以用弱引用解决
public void onDestroy() {
mContext = null;
mView = null;
}
public void onStart() {
}
public void onStop() {
}
public void onResume() {
}
public void onPause() {
}
public void onRestart(){}
public void onSave(Bundle savedInstance) {
}
public void onRestore(Bundle savedInstance) {
}
public T getView(){
return mView;
}
public Context getContext(){
return mContext;
}
}
BasePresenter代码很简单,主要是生命周期的空实现和接收View层实例的构造方法。
BaseMVPActivity
public abstract class BaseMVPActivity<T extends IPresenter> extends AppCompatActivity implements IMVPView {
protected T mPresenter;
private WeakReference<BasePresenter> delegate;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutID());
mPresenter = createPresenter();
//mPresenter和delegate指向同一个实例,对开发者进行规范,若P层实现类不是BasePresenter的子类则报错
if (mPresenter instanceof BasePresenter) {
delegate = new WeakReference<BasePresenter>((BasePresenter) mPresenter);
} else {
throw new IllegalArgumentException("Presenter must extends BasePresenter");
}
bindViews();
preCreate(savedInstanceState);
delegate.get().onCreate(savedInstanceState);
postCreate(savedInstanceState);
}
/**
* Create Presenter for this Activity.
*/
protected abstract T createPresenter();
protected T getPresenter(){
return mPresenter;
}
/**
* You can do something after Presenter Created in this method.
* 在Presenter的onCreate方法调用之后执行
*/
protected void postCreate(Bundle savedInstanceState) {
}
/**
* You can do something before Presenter Created in this method.
* 在Presenter的onCreate方法调用之前执行
*/
protected void preCreate(Bundle savedInstanceState) {
}
/**
* Bind view for this activity.
*/
protected abstract void bindViews();
/**
* Simple way to findView without cast the type.
*/
public <T extends View> T findView(int id) {
return (T) findViewById(id);
}
@Override
protected void onDestroy() {
super.onDestroy();
delegate.get().onDestroy();
mPresenter = null;
}
@Override
protected void onStart() {
super.onStart();
delegate.get().onStart();
}
@Override
protected void onStop() {
super.onStop();
delegate.get().onStop();
}
@Override
protected void onResume() {
super.onResume();
delegate.get().onResume();
}
@Override
protected void onPause() {
super.onPause();
delegate.get().onPause();
}
@Override
protected void onRestart() {
super.onRestart();
delegate.get().onRestart();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
delegate.get().onSave(outState);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
delegate.get().onRestore(savedInstanceState);
}
}
之前说过,MingMVP的Presenter的”当家作主”并不是真的当家作主,实际还是需要View层驱动其生命周期,对于使用MingMVP框架的同学确实是当家作主。只不过BaseActivity等View层基类帮我们简化大部分MVP实现步骤。这样我们就能简洁而又优雅的实现MVP开发模式。同时在BasePresenter和BaseActivity通过泛型规定了双方互相开放的VP接口,这样使用MingMVP的开发者在V层实现中只能调用XXXContract中的Presenter接口而不能调用Presenter的生命周期方法,P层也只能调用XXXContract中的View接口,真正实现VP分离。
总结
MingMVP能帮助开发者简化MVP模式开发工作。框架已上传jcenter,在AndroidStudio可直接引用。附上MingMVP的github地址,喜欢的记得点star哦。
Github MingMVP
上一篇: vue中如何实现pdf文件预览的方法