Android MVP登录小例子

作者: wmjwmj | 来源:发表于2018-07-24 11:25 被阅读10次

1. MVP简介略

1.1 Model
业务逻辑。如访问网络、数据库
实体类

1.2 View
该页面的逻辑,需要做什么动作,反馈,交互等

1.3 Presenter
负责View和Model的交互

2. 登录模块例子

LoginModel为登录的网络操作。略

2.1 LoginView接口
抽象登录页面需要的一些逻辑

public interface LoginView {

    /**
     * 获取用户名称
     */
    String getUserName();

    /**
     * 获取用户密码
     */
    String getPassword();

    /**
     * 处理登录结果
     */
    void onLoginResult(String result);

}

2.2 LoginActivity
实现LoginView接口。持有LoginPresenter的引用

public class LoginActivity extends AppCompatActivity implements LoginView {

    @BindView(R.id.et_username)
    EditText mEtUsername;
    @BindView(R.id.et_password)
    EditText mEtPassword;

    // 持有LoginPresenter的引用
    private LoginPresenter mLoginPresenter;

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

    @Override
    public String getUserName() {
        return mEtUsername.getText().toString();
    }

    @Override
    public String getPassword() {
        return mEtPassword.getText().toString();
    }

    @Override
    public void onLoginResult(String result) {
        // 处理登录结果
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getApplicationContext(), result, Toast.LENGTH_SHORT).show();
            }
        });
    }

    @OnClick(R.id.btn_login)
    public void onViewClicked() {

    }

}

2.3 LoginPresenter
持有LoginView接口的引用,持有LoginModel的引用。构造函数传入view,实例化model。根据LoginModel提供登录方法

public class LoginPresenter {

    // 持有LoginView接口的引用
    private LoginView mLoginView;
    // 持有LoginModel的引用
    private LoginModel mLoginModel;

    // 传入LoginView
    public LoginPresenter(LoginView loginView) {
        mLoginView = loginView;
        // 实例化LoginModel
        mLoginModel = new LoginModel();
    }

    /**
     * 登录
     */
    public void login(){
        mLoginModel.login(mLoginView.getUserName(), mLoginView.getPassword(), new LoginCallback() {
            @Override
            public void onLoginResult(String result) {
                if (null != mLoginView) {
                    // 回调到UI层
                    mLoginView.onLoginResult(result);
                }
            }
        });
    }

}

2.4 回到LoginActivity
实例化LoginPresenter,传入this。实现登录方法

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        ButterKnife.bind(this);
        // 实例化LoginPresenter
        mLoginPresenter = new LoginPresenter(this);
    }

    @OnClick(R.id.btn_login)
    public void onViewClicked() {
        mLoginPresenter.login();
    }

3.优化

3.1 Presenter一直持有View的引用,如何解除?
LoginPresenter提供绑定View和解绑View的方法

public class LoginPresenter {

    // 持有LoginView接口的引用
    private LoginView mLoginView;
    // 持有LoginModel的引用
    private LoginModel mLoginModel;

    public LoginPresenter() {
        // 实例化model
        mLoginModel = new LoginModel();
    }

    /**
     * 绑定View
     */
    public void attachView(LoginView loginView){
        mLoginView = loginView;
    }

    /**
     * 解绑View
     */
    public void detachView(){
        mLoginView = null;
    }
    
    ···
}

LoginActivity在onCreate()中绑定View,在onDestroy中解绑View

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        ButterKnife.bind(this);
        // 实例化LoginPresenter
        mLoginPresenter = new LoginPresenter();
        // 绑定
        mLoginPresenter.attachView(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 解绑
        mLoginPresenter.detachView();
    }

3.2 多个Presenter,都要写绑定和解绑的方法,如何复用?把绑定和解绑的方法封装到父类,LoginView写死了怎么办?
BasePresenter持有View的引用,类型是泛型。封装绑定View和解绑View的方法

public class BasePresenter<V extends BaseView> {

    private V mView;

    public V getView() {
        return mView;
    }

    /**
     * 绑定View
     */
    public void attachView(V view){
        mView = view;
    }

    /**
     * 解绑View
     */
    public void detachView(){
        mView = null;
    }

}
  1. 3 多个Activity,都要写绑定和解绑的方法,如何复用?
    BaseActivity持有View和Presenter的引用。提供抽象方法让其子类实例化View和Presenter。onCreate()中绑定View,调用抽象方法,onDestroy()中解绑View。BaseFragment、BaseListView等同理
public abstract class BaseActivity<V extends BaseView, P extends BasePresenter<V>> extends AppCompatActivity{

    // 持有View的引用
    private V mView;
    // 持有Presenter的引用
    private P mPresenter;

    public P getPresenter() {
        return mPresenter;
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (null == mView) {
            mView = createView();
        }
        if (null == mPresenter) {
            mPresenter = createPresenter();
        }
        if (null == mView) {
            throw new NullPointerException("view can not be null!");
        }
        if (null == mPresenter) {
            throw new NullPointerException("presenter can not be null!");
        }
        // 绑定view
        mPresenter.attachView(mView);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 解绑view
        mPresenter.detachView();
    }

    /**
     * 创建view
     */
    public abstract V createView();

    /**
     * 创建presenter
     */
    public abstract P createPresenter();

}
public class LoginActivity extends BaseActivity<LoginView, LoginPresenter> implements LoginView{

    @BindView(R.id.et_username)
    EditText mEtUsername;
    @BindView(R.id.et_password)
    EditText mEtPassword;

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

    @Override
    public LoginView createView() {
        return this;
    }

    @Override
    public LoginPresenter createPresenter() {
        return new LoginPresenter();
    }

    @Override
    public String getUserName() {
        return mEtUsername.getText().toString();
    }

    @Override
    public String getPassword() {
        return mEtPassword.getText().toString();
    }

    @Override
    public void onLoginResult(final String result) {
        // 处理登录结果
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getApplicationContext(), result, Toast.LENGTH_SHORT).show();
            }
        });
    }

    @OnClick(R.id.btn_login)
    public void onViewClicked() {
        getPresenter().login();
    }

}

相关文章

网友评论

    本文标题:Android MVP登录小例子

    本文链接:https://www.haomeiwen.com/subject/tdeemftx.html