Android开发 MVP之初体验

MVP

Android开发 MVP之初体验

标签(空格分隔):Android MVP MVC

---
本文为作原创,转载时请写上转载地址:http://www.bit100.com/android开发-mvp之初体验

熟悉安卓开发的童鞋应该都熟悉MVC架构模式, MVC开发模式即:
Model(模型) -- View(视图) -- Control(控制器)
逻辑图如下:
MVC

而这种开发模式有个缺点,就是在项目越来越大时,文件会越来越多,查找起来很不方便,而且Activity或者Fragment里面的代码会越来越臃肿,看起来很凌乱,要修改更是让人头疼,于是就提出了一种MVP的开发模式,MVP开发模式即:
Model(模型) -- View(视图) -- Presente(任命者/中介)
逻辑图如下:
MVP

网上有很多讲解MVP的文章和教程,我这里就不详细介绍了,但还有很多人看过教程之后依然不知如何实现MVP,今天主要通过实际代码的方式来体验MVP开发

本次使用的代码为Github上的一个开源项目,名为androidmvp

传送门 http://github.com/antoniolg/androidmvp

先看看界面

界面很简单,就是一个登录界面和一个ListView填充的主界面,登录之后跳转到主界面,主界面上显示一个列表
登录界面主界面

第一步

用Android Studio打开项目之后可以看到如下的项目结构
项目结构

通过截图可以看出,该项目是根据界面来分类的,Login文件夹下放的是所有与登录界面有关的文件,main文件夹下放的是所有与主界面有关的文件

其中, Login文件夹下共有6个文件, 3个类文件, 3个接口文件

类文件:
  • LoginActivity
  • LoginInteratorImpl
  • LoginPresenterImpl
接口文件:
  • LoginView
  • LoginInteractor
  • LoginPresenter

第二步

打开LoginActivity.java文件

public class LoginActivity extends Activity implements LoginView, View.OnClickListener {

private ProgressBar progressBar;
private EditText username;
private EditText password;
private LoginPresenter presenter;

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

    //实例化控件
    ...

    presenter = new LoginPresenterImpl(this);
}
...


从上面代码可以看出,该Activity实现了LoginView的接口和View的点击事件, 并且实例化了一个LoginPresenterImpl对象

现在打开LoginView.java

public interface LoginView {
void showProgress();

void hideProgress();

void setUsernameError();

void setPasswordError();

void navigateToHome();
}


可以看到LoginView文件中定义了几个接口, 通过名称可以很容易知道每个接口是用来干什么的
返回LoginActivity也很容易发现是如何实现这几个接口的,如下:

@Override public void showProgress() {
progressBar.setVisibility(View.VISIBLE);
}

@Override public void hideProgress() {
progressBar.setVisibility(View.GONE);
}

@Override public void setUsernameError() {
username.setError(getString(R.string.username_error));
}

@Override public void setPasswordError() {
password.setError(getString(R.string.password_error));
}

@Override public void navigateToHome() {
startActivity(new Intent(this, MainActivity.class));
finish();
}


打开LoginPresenter.java

public interface LoginPresenter {
void validateCredentials(String username, String password);

void onDestroy();
}


可以看到定义了两个接口,其中validateCredentials接口是用来验证用户名和密码是否通过验证的
在LoginActivity中也有实现

@Override public void onClick(View v) {
presenter.validateCredentials(username.getText().toString(), 
    password.getText().toString());
}


看到这里, 我们可以总结出LoginActivity没有做任何逻辑相关的事情,而是在做界面显示相关和界面跳转的事情, 就连验证帐号的逻辑都是交给LoginPresenterImpl类的

那么现在顺藤摸瓜,打开LoginPresenterImpl.java文件

public class LoginPresenterImpl implements LoginPresenter, 
    LoginInteractor.OnLoginFinishedListener {

private LoginView loginView;
private LoginInteractor loginInteractor;

public LoginPresenterImpl(LoginView loginView) {
    this.loginView = loginView;
    this.loginInteractor = new LoginInteractorImpl();
}

//其他方法的实现
...
}


我们可以看到该类实现了LoginPresenter和LoginInteractor.OnLoginFinishedListener的接口, 并且在构造方法的参数为LoginView, 那么问题来了, 为什么要传递LoginView类型的参数呢?

我们刚才也看到了,在LoginView中定义了几个接口, 而在LoginActivity中有对这几个接口的实现, 所以传递这个参数, 是有利于LoginPresenterImpl类调用LoginActivity的实现方法, 用于界面上的显示, 这就达到了逻辑代码和显示代码的分离

好了,现在来看看是怎么实现LoginPresenter中的validateCredentials接口的吧

@Override public void validateCredentials(String username, String password) {

if (loginView != null) {
    loginView.showProgress();
}

loginInteractor.login(username, password, this);
}


看到这里,有同学该有疑问了,为什么在这个方法里我没看到实现帐号验证的具体逻辑呢?

没错,这里不应该有帐号验证的具体逻辑代码,因为LoginPresenterImpl类充当的是任命者或者称中介者的身份, 中介者只负责联系界面类具体实现逻辑代码的类,如果还不能理解,就想想房地产中介吧, 他们只负责联系买房者和卖房者, 其他的事都不管(抱歉, 我没有鄙视或看不起房地产中介人员的意思, 这里只是做个举例, 在此说声对不起).

我们看到代码中, 把接收到的username和password参数传递给了一个login方法, 该方法在LoginInteractor文件中, 我们再打开LoginInteractor.java文件

public interface LoginInteractor {

interface OnLoginFinishedListener {
    void onUsernameError();

    void onPasswordError();

    void onSuccess();
}

void login(String username, String password, OnLoginFinishedListener listener);

}


可以定义了一个login接口和一个OnLoginFinishedListener接口类, 返回LoginPresenterImpl.java文件可以很容易看到OnLoginFinishedListener接口类中接口的实现

@Override public void onUsernameError() {
if (loginView != null) {
    loginView.setUsernameError();
    loginView.hideProgress();
}
}

@Override public void onPasswordError() {
if (loginView != null) {
    loginView.setPasswordError();
    loginView.hideProgress();
}
}

@Override public void onSuccess() {
if (loginView != null) {
    loginView.navigateToHome();
}
}


在这些接口的实现中同样只是调用LoginView中的接口,并没有具体的逻辑操作代码

在该类的构造方法中我们会发现, 这里实例化了一个LoginInteractorImpl对象, 我们现在打开LoginInteractorImpl.java文件

public class LoginInteractorImpl implements LoginInteractor {

@Override
public void login(final String username, final String password, final OnLoginFinishedListener listener) {

    // Mock login. I'm creating a handler to delay the answer a couple of seconds
    new Handler().postDelayed(new Runnable() {

        @Override public void run() {

            boolean error = false;
            if (TextUtils.isEmpty(username)){
                listener.onUsernameError();
                error = true;
            }
            if (TextUtils.isEmpty(password)){
                listener.onPasswordError();
                error = true;
            }
            if (!error){
                listener.onSuccess();
            }
        }
    }, 2000);
}
}


我们可以看到该类实现了LoginInteractor中的login接口, 并且在login方法中进行了具体的逻辑处理, 如果验证通过, 调用onSuccess接口

好了,整个登录流程讲完了,最后我们再来梳理一下整个流程:

  1. 在LoginActivity中,通过LoginPresenter接口类中的validateCredentials接口,把username和password传递给LoginPresenter的实现类LoginPresenterImpl
  2. LoginPresenterImpl类再通过LoginInteractor接口类中的login接口, 把username和password传递给LoginInteractor的实现类LoginInteractorImpl
  3. 在LoginInteractorImpl类中进行具体的逻辑处理, 如果验证通过,则调用LoginInteractor.OnLoginFinishedListener接口类中的onSuccess接口, 即调用了LoginPresenterImpl类中实现的onSuccess接口
  4. LoginPresenterImpl类中实现的onSuccess接口中,调用了LoginView接口类中的navigateToHome接口,即调用了LoginActivity类中实现的navigateToHome接口
  5. 最后在navigateToHome接口中实现Activity的跳转,跳转到MainActivity
流程图如下:
流程图

总结

在MVP开发模式中, Activity只负责界面的显示和跳转相关的操作, 具体的逻辑处理通过调用接口来传递给Presenter(中介者) 既不做界面显示的操作,也不做具体的逻辑处理操作, 具体的逻辑处理通过调用接口,让Interactor即交互类来完成

交互类的逻辑处理结果,通过调用Presenter中实现的接口, 再由Presenter要实现的接口中调用Activity中实现的接口来进行UI的显示或界面跳转

最后

好了,安卓开发 MVP之初体验讲完了,写了那么多,希望大家能够看懂了,如果还有什么问题,可以问我Follow Me
1 分享
ask
ask

ask

赞,好文章!
前面2张站外的图不能显示,需要上传图片附件才能看呢!
0 赞 2016-03-28 23:38
MOLVMIN

MOLVMIN

虽然没有看明白,但是觉得逻辑很清晰,要好好学习学习!
0 赞 2016-03-30 14:57

要回复文章请先登录注册