qmsggg_BlogCollect icon indicating copy to clipboard operation
qmsggg_BlogCollect copied to clipboard

Android 开发模式总结

Open qmsggg opened this issue 7 years ago • 5 comments

  1. MVVM模式
  2. MVP模式

qmsggg avatar Oct 15 '17 15:10 qmsggg

MVP模式总结

qmsggg avatar Dec 15 '17 17:12 qmsggg

最全安卓架构

qmsggg avatar Dec 15 '17 17:12 qmsggg

google MVP

qmsggg avatar Dec 15 '17 17:12 qmsggg

Android mvp模式

MVP模式介绍

相信大家对MVC都是比较熟悉了:M-Model-模型、V-View-视图、C-Controller-控制器,MVP作为MVC的演化版本,那么类似的MVP所对应的意义:M-Model-模型、V-View-视图、P-Presenter-表示器。 从MVC和MVP两者结合来看,Controlller/Presenter在MVC/MVP中都起着逻辑控制处理的角色,起着控制各业务流程的作用。而 MVP与MVC最不同的一点是M与V是不直接关联的也是就Model与View不存在直接关系,这两者之间间隔着的是Presenter层,其负责调控 View与Model之间的间接交互。在 Android中很重要的一点就是对UI的操作基本上需要异步进行也就是在MainThread中才能操作UI,所以对View与Model的切断分离是 合理的。此外Presenter与View、Model的交互使用接口定义交互操作可以进一步达到松耦合也可以通过接口更加方便地进行单元测试。所以也就有了这张图片(MVP和MVC的对比) image

MVP和MVC的对比

其实最明显的区别就是,MVC中是允许Model和View进行交互的,而MVP中很明显,Model与View之间的交互由Presenter完成。还有一点就是Presenter与View之间的交互是通过接口的(代码中会体现)。

MVP实例

  • presenter层描述和具体代码

Presenter扮演着view和model的中间层的角色。获取model层的数据之后构建view层;也可以收到view层UI上的反馈命令后分发处理逻辑,交给model层做业务操作。它也可以决定View层的各种操作。

package com.example.qmsggg.androidmvpeg;

/**
 * Created by qmsggg on 2018/3/23.
 */

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

    void onDestroy();
}
package com.example.qmsggg.androidmvpeg;

/**
 * Created by qmsggg on 2018/3/23.
 */

public class LoginPresenterImpl implements LoginPresenter, OnLoginFinishedListener {
    private LoginView mLoginView;
    private LoginModel mLoginModel;

    public LoginPresenterImpl(LoginView loginView) {
        this.mLoginView = loginView;
        this.mLoginModel = new LoginModelImpl();
    }

    @Override
    public void validateCredentials(String username, String password) {
        if (mLoginView != null) {
            mLoginView.showProgress();
        }

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

    @Override
    public void onDestroy() {
        mLoginView = null;
    }

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

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

    @Override
    public void onSuccess() {
        if (mLoginView != null) {
            mLoginView.navigateToHome();
            mLoginView.hideProgress();
        }
    }
}
  • view层描述和具体代码

负责显示数据、提供友好界面跟用户交互就行。MVP下Activity和Fragment以及View的子类体现在了这一 层,Activity一般也就做加载UI视图、设置监听再交由Presenter处理的一些工作,所以也就需要持有相应Presenter的引用。本层所需要做的操作就是在每一次有相应交互的时候,调用presenter的相关方法就行。(比如说,button点击)

package com.example.qmsggg.androidmvpeg;

/**
 * Created by qmsggg on 2018/3/23.
 */

public interface LoginView {
    void showProgress();

    void hideProgress();

    void setUsernameError();

    void setPasswordError();

    void navigateToHome();
}

package com.example.qmsggg.androidmvpeg;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;

public class LoginActivity extends AppCompatActivity 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_main);

        progressBar = (ProgressBar) findViewById(R.id.progress);
        progressBar.setVisibility(View.GONE);
        username = (EditText) findViewById(R.id.username);
        password = (EditText) findViewById(R.id.password);
        findViewById(R.id.button).setOnClickListener(this);

        presenter = new LoginPresenterImpl(this);
    }

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

    @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() {
        Toast.makeText(this,"login success",Toast.LENGTH_SHORT).show();
    }
}
  • model层描述和具体代码

提供我们想要展示在view层的数据和具体登陆业务逻辑处理的实现,

package com.example.qmsggg.androidmvpeg;

/**
 * Created by qmsggg on 2018/3/23.
 */

public interface LoginModel {
    void login(String username, String password, OnLoginFinishedListener listener);
}

package com.example.qmsggg.androidmvpeg;


import android.os.Handler;
import android.text.TextUtils;

/**
 * Created by qmsggg on 2018/3/23.
 */

public class LoginModelImpl implements LoginModel {
    @Override
    public void login(final String username, final String password, final OnLoginFinishedListener listener) {
        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);
    }
}
  • 登陆的回调接口
package com.example.qmsggg.androidmvpeg;

/**
 * Created by qmsggg on 2018/3/23.
 */

public interface OnLoginFinishedListener {
    void onUsernameError();

    void onPasswordError();

    void onSuccess();
}

1 Activity做了一些UI初始化的东西并需要实例化对应LoginPresenter的引用和实现 LoginView的接口,监听界面动作 2 登陆按钮按下后即接收到登陆的事件,在onClick里接收到即通过LoginPresenter的引用把它交给LoginPresenter处理。LoginPresenter接收到了登陆的逻辑就知道要登陆了 3 然后LoginPresenter显示进度条并且把逻辑交给我们的Model去处理,也就是这里面的LoginModel,(LoginModel的实现类LoginModelImpl),同时会把OnLoginFinishedListener也就是LoginPresenter自身传递给我们的Model(LoginModel)。 4 LoginModel处理完逻辑之后,结果通过OnLoginFinishedListener回调通知LoginPresenter 5 LoginPresenter再把结果返回给view层的Activity,最后activity显示结果 请参考这张类图: image

qmsggg avatar Mar 23 '18 07:03 qmsggg

工作中用到的mvp模式其实是这样的

基类如下,在p中继承下面的类,在v中实现回调,这样就把model层直接略过了,用的有点不对

import rx.subscriptions.CompositeSubscription;

/**
 * Presenter基类
 */
public class BasePresenter<T> {

    protected CompositeSubscription subscriptions = new CompositeSubscription();

    private T mView;

    public void attach(T t) {
        mView = t;
    }

    public T getView() {
        return mView;
    }

    public void detach() {
        mView = null;
        subscriptions.unsubscribe();
    }
}

qmsggg avatar Mar 23 '18 07:03 qmsggg