欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android应用MVP实践——MingMVP

程序员文章站 2022-06-08 22:25:14
...

前言

    在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个文件。
Android应用MVP实践——MingMVP
以下是对每个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