Android MVP模式

Android MVP模式

  • View 对应于Activity,负责View的绘制以及与用户交互
  • Model 依然是业务逻辑和实体模型
  • Presenter 负责完成View于Model间的交互

mvp模式简化的Activity的代码逻辑,将复杂的逻辑代码提取到了Presenter中进行处理。对应的耦合度降低。

一张图总结Mvc和Mvp的区别

20150622212916054.png

其实最明显的区别就是,MVC中中Model和View直接交互的,而MVP中很明显,Model与View之间的交互由Presenter完成,Presenter与View之间的交互是通过接口的。

Android Demo

需求:页面上有一个按钮,点击后去请求数据,成果后改变页面显示。

不使用mvp:

public class NotMvpActivity extends AppCompatActivity {

    private Button bt;
    private TextView tv;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_demo);

        bt = (Button) findViewById(R.id.bt);
        tv = (TextView) findViewById(R.id.tv);

        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                requestData();
            }
        });

    }

    /**
     * 获取数据
     */
    private void requestData() {

        tv.setText("加载中");

        new Thread() {
            @Override
            public void run() {
                super.run();

                SystemClock.sleep(2000);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tv.setText("成功获取到数据");
                    }
                });

            }
        }.start();

    }
}

以上应该是最原始的方法,下面使用mvp改造。

步骤:

1、创建接口,定义页面可能会出现的情况(加载中,成功,失败)。

2、Activity实现接口,成功View层。

3、创建一个类,实现网络请求的操作,Model层。

4、创建一个类,处理Model和View之间的通信,Presenter层。

1、view层的接口:

/**
 * @project:MvpDemo
 * @author:小卷子
 * @date 2018/6/29
 * @describe:View层接口 定义页面可能会出现的情况(加载中,成功,失败)
 * @fix:
 */
public interface DemoView {

    /**
     * 加载中
     */
    void Loading();
    /**
     * 获取成功
     */
    void getDataSuccess();
    /**
     * 获取失败
     */
    void getDataFail();
}

2、让Activity实现这个接口中的方法

public class DemoAcitivity extends AppCompatActivity implements DemoView {


    private Button bt;
    private TextView tv;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_demo);

        bt = (Button) findViewById(R.id.bt);
        tv = (TextView) findViewById(R.id.tv);

    }

    @Override
    public void Loading() {
        tv.setText("加载中");
    }

    @Override
    public void getDataSuccess() {
        tv.setText("成功");
    }

    @Override
    public void getDataFail() {
        tv.setText("失败");
    }
}

3、创建一个类,用来封装之前的网络请求。(DemoModelCallBack是网络请求的回调,demo只是简单模拟)

/**
 * @project:MvpDemo
 * @author:小卷子
 * @date 2018/6/29
 * @describe:Mode1层 请求数据
 * @fix:
 */
public class DemoMode1 {
    
    public void getData(final DemoModelCallBack callBack) {

        new Thread() {
            @Override
            public void run() {
                super.run();
                SystemClock.sleep(2000);

                if (callBack != null) {
                    callBack.getDataSuccess();
                }
            }
        }.start();
    }

}

4、处理Model和View之间的通信,Presenter

/**
 * @project:MvpDemo
 * @author:小卷子
 * @date 2018/6/29
 * @describe:Presenter处理v和m的通信
 * @fix:
 */
public class DemoPresenter {

    private DemoModel demoModel;
    private DemoView demoView;

    public DemoPresenter(DemoModel demoModel, DemoView demoView) {
        this.demoModel = demoModel;
        this.demoView = demoView;
    }

    /**
     * 请求数据
     */
    public void getData() {
        //view处理请求中
        demoView.Loading();
        //去请求数据
        demoMode1.getData(new DemoModelCallBack() {
            @Override
            public void getDataSuccess() {
                demoView.getDataSuccess();
            }

            @Override
            public void getDataFail() {
                demoView.getDataFail();
            }
        });
        
    }
}

5、最后调整一下Activity ,Activity处理需要实现View层的接口,还要在自身创建Persenter。Activity接收到用户的事件时全部交给Persenter来处理。Persenter处理事件后将结果反馈到View(也就是Activity)。所以思路大概是这样:

  • Activity需要实现View层接口
  • Persenter需要持有View层引用和Model层引用
  • 在Activity中创建Persenter,通过Persenter连接自身和Model

调整后的Activity

/**
 * @project:MvpDemo
 * @author:小卷子
 * @date 2018/6/29
 * @describe:Activity实现view接口
 * @fix:
 *
 */

public class DemoAcitivity extends AppCompatActivity implements DemoView {


    private Button bt;
    private TextView tv;
    private DemoPresenter demoPresenter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_demo);

        bt = (Button) findViewById(R.id.bt);
        tv = (TextView) findViewById(R.id.tv);

        demoPresenter = new DemoPresenter(this);

        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //点击事件交给 demoPresenter处理
                demoPresenter.getData();
            }
        });

    }




    @Override
    public void Loading() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                tv.setText("加载中");
            }
        });
    }

    @Override
    public void getDataSuccess() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                tv.setText("成功");
            }
        });
    }

    @Override
    public void getDataFail() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                tv.setText("失败");
            }
        });
    }
}

简单的Demo模式的MVP架构存在很多问题不能应用到实际开发中。(代码冗余,复用性差)。所以针对这些问题需要进行优化。

调用View可能引发的空指针异常

以上例子中请求网络数据等待反馈后跟新到页面,但是在请求过程中当前的View可能被销毁,Presenter在网络回调后调用View更新就会引发空指针。要避免这种情况就要在每次调用View的时候都需要知道View是否存在。也就是Presenter必须知道Activity的生命状态。

Presenter中新增:

    /**
     * 绑定
     *
     * @param demoView
     */
    public void attachView(DemoView demoView) {
        this.demoView = demoView;
        this.demoModel = new DemoModel();
    }

    /**
     * 解除绑定
     */
    public void detachView() {
        this.demoView = null;
        //todo DemoModel取消网络请求
    }


    /**
     * 当前是否与View建立连接
     * 每次调用view的时候先调用此方法检查
     * @return
     */
    public boolean isViewAttached() {
        return demoView != null;
    }
  • attachView() 绑定View引用。
  • detachView 断开View引用。
  • isViewAttached() 判断View引用是否存在。

Presenter与View的绑定不在通过构造传入,通过attachView()detachView 绑定生命周期,每次调用View之前判断是否存在。

你可能感兴趣的:(Android MVP模式)