详细讲解Android在MVP模式下实现简单的登录注册

MVP模式

简称:MVP 全称:Model-View-Presenter ;MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。

这张图可以很清晰的看出MVP各层的职责,简单来说

M层,即Model数据模型层,主要用来提供数据

V层,即VIew视图层,用来展示视图-------由Activity充当

P层,即preserter逻辑层,他是VIew层和Model层的桥梁,也是MVP模式的特点

MVP模式有哪些优点呢

 MVP模式是由MVC模式演化而来,在MVC模式中,Activity即充当了View又充当了Controller,这样就导致Activity中的代码可能会非常的臃肿,MVP模式就很好的解决了这个问题。

具体的优点:

1、模型与视图完全分离,我们可以修改视图而不影响模型

2、可以更高效地使用模型,因为所有的交互都发生在一个地方--Presenter内部

3、我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁。

4、如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试)

如何使用MVP

既然MVP模式这么好用,那我们应该如何使用呢,接下来通过一个用户登录的demo来解析MVP模式

项目分包:

这里主要分成了di和ui两个包,di处理数据逻辑即M层和P层,ui处理页面即V层。

创建契约类

我个人认为创建契约类的方法非常好,帮助我们管理MVP中的接口,一目了然。

契约类的代码如下

public interface IContract {
    public interface IView{
        void ShowData(String msg);
    }
    public interface IPresenter<IView>{
        void resqusetMesg(String name,String pwd);
        void attachView(IView iView);
        void deattachView(IView iView);
    }
    public interface IModel{
        public interface CallBack{
            void responseData(String msg);
        }
        void requestData(String name,String pwd,CallBack callBack);
    }
}

非常容易可以看出,这一个接口托管了MVP三层的接口

Activity中

刚才已经介绍过了,在MVP中Acticity主要负责的是view的操作

所以我们的Acticity需要实现View的接口,重写View中的方法

到这里Activity如下

public class MainActivity extends AppCompatActivity implements IContract.IView {
       @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        }
       @Override
    public void ShowData(String msg) {
        }

之后我们的view层应该与p层进行关联,也就是我们的Activity中需要持有p层的引用

private IContract.IPresenter presenter;

 刚刚说过,p层主要是逻辑层,处理View层的数据

所以当我们点击按钮之后,应该把输入框中的内容传到P层中进行非空判断或者其他的逻辑判断

而且P层要和View进行关联,所以在持有P层的引用之后,应该调用P层的方法与View进行关联

        //绑定当前的视图
        presenter.attachView(this);

所以onCreate中如下

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        presenter = new PresenterImpl();
        //绑定当前的视图
        presenter.attachView(this);
        name = findViewById(R.id.text_name);
        pwd = findViewById(R.id.text_pwd);
        button = findViewById(R.id.btn_login);
        //点击按钮获取文本内容
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String name = MainActivity.this.name.getText().toString();
                String pwd = MainActivity.this.pwd.getText().toString();
                //传到P层
                presenter.resqusetMesg(name,pwd);
            }
        });
    }

 之后我们再看重写的方法

Activity是负责View的,也就是UI,重写的方法也就是更新UI的方法

所以我们重写的方法中代码如下

 @Override
    public void ShowData(final String msg) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(MainActivity.this,msg,Toast.LENGTH_SHORT).show();
            }
        });

    }

 之后我们重写onDestroy方法,销毁视图

 @Override
    protected void onDestroy() {
        presenter.deattachView(this);
        super.onDestroy();
    }

到这里Activity中的所有代码就完成了

Activity中的所有代码如下: 

public class MainActivity extends AppCompatActivity implements IContract.IView {
    private IContract.IPresenter presenter;
    private EditText name;
    private EditText pwd;
    private Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        presenter = new PresenterImpl();
        presenter.attachView(this);
        name = findViewById(R.id.text_name);
        pwd = findViewById(R.id.text_pwd);
        button = findViewById(R.id.btn_login);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String name = MainActivity.this.name.getText().toString();
                String pwd = MainActivity.this.pwd.getText().toString();
                presenter.resqusetMesg(name,pwd);
            }
        });
    }

    @Override
    public void ShowData(final String msg) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(MainActivity.this,msg,Toast.LENGTH_SHORT).show();
            }
        });

    }

    @Override
    protected void onDestroy() {
        presenter.deattachView(this);
        super.onDestroy();
    }
}

P层的实现类

首先先实现P层的接口,重写里面的方法

public class PresenterImpl implements IContract.IPresenter<IContract.IView> {
    @Override
    public void resqusetMesg(String name, String pwd) {
    }
    @Override
    public void attachView(IContract.IView iView) {
    }
    @Override
    public void deattachView(IContract.IView iView) {
    }

}

P层就是view层和model层的一个桥梁

所以在P层中需要持有VIew层和Model层的引用,并且定义一个弱引用防止内存泄漏

    private IContract.IView iView;
    private IContract.IModel iModel;
    private WeakReference<IContract.IView> iViewWeakReference;
    private WeakReference<IContract.IModel> iModelWeakReference;

 接下来,看一下重写的方法的作用

首先  resqusetMesg 方法,用来接收View传过来的数据,并进行逻辑操作

这里主要思路是先进行非空判断,如果不为空的话到Model层中去请求数据,然后通过接口回调把结果返回到View层

所以这个方法中的代码如下

 @Override
    public void resqusetMesg(String name, String pwd) {
        if (name !=null){
            iModel.requestData(name, pwd, new IContract.IModel.CallBack() {
                @Override
                public void responseData(String msg) {
                    iView.ShowData(msg);
                }
            });
        }
    }

接下来  attachView 方法

这个方法的主要作用就是让P层和VIew层建立联系

代码如下:

 @Override
    public void attachView(IContract.IView iView) {
        this.iView = iView;
        iModel = new ModelImpl();
        iModelWeakReference = new WeakReference<>(iModel);
        iViewWeakReference = new WeakReference<>(iView);
    }

 最后 deattachView 方法

显而易见也就是销毁View的方法

@Override
    public void deattachView(IContract.IView iView) {
        iViewWeakReference.clear();
        iModelWeakReference.clear();
    }

至此P层就全部写完了

P层的全部代码如下 :

public class PresenterImpl implements IContract.IPresenter<IContract.IView> {
    private IContract.IView iView;
    private IContract.IModel iModel;
    private WeakReference<IContract.IView> iViewWeakReference;
    private WeakReference<IContract.IModel> iModelWeakReference;
    @Override
    public void resqusetMesg(String name, String pwd) {
        if (name !=null){
            iModel.requestData(name, pwd, new IContract.IModel.CallBack() {
                @Override
                public void responseData(String msg) {
                    iView.ShowData(msg);
                }
            });
        }
    }

    @Override
    public void attachView(IContract.IView iView) {
        this.iView = iView;
        iModel = new ModelImpl();
        iModelWeakReference = new WeakReference<>(iModel);
        iViewWeakReference = new WeakReference<>(iView);
    }

    @Override
    public void deattachView(IContract.IView iView) {
        iViewWeakReference.clear();
        iModelWeakReference.clear();
    }
}

M层的实现类

Model层是数据模型层,也就是主要负责请求数据的

首先先实现Model层的接口,重写里面的方法

public class ModelImpl implements IContract.IModel {

    @Override
    public void requestData(String name, String pwd, CallBack callBack) {

    }

}

之后我们通过OKHttp访问网络数据,也可以根据需求选择其他的网络请求框架

通过post请求,将我们拿到的用户名和密码到网上进行查询,并将查询到的结果返回

Model层的所有代码如下 :

public class ModelImpl implements IContract.IModel {

    @Override
    public void requestData(String name, String pwd, final CallBack callBack) {
        String url = "https://www.zhaoapi.cn/user/login";
        OkHttpClient okHttpClient = new OkHttpClient
                .Builder()
                .writeTimeout(15, TimeUnit.SECONDS)
                .readTimeout(15, TimeUnit.SECONDS)
                .build();
        FormBody build = new FormBody
                .Builder()
                .add("mobile", name)
                .add("password", pwd)
                .build();
        Request request = new Request.Builder().url(url).post(build).build();
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String msg = response.body().string();
                callBack.responseData(msg);
            }
        });
    }
}

思路整理

1.首先先写一个契约类,管理MVP的全部接口

2.让MainActivity继承View的接口,重写方法

3.MainActivity持有P层的引用,点击按钮把获取到的内容传到P层进行逻辑操作

4.写P层的实现类,判断内容,如果没有问题把数据传到M层

5.写M层的实现类,主要进行请求数据的操作

6.请求成功,把结果返回View层展示

注意:内存泄漏的问题

希望这篇文章对你的MVP学习有所帮助

猜你喜欢

转载自blog.csdn.net/Do_the_best_/article/details/82624598