Android MVP-编程思想2(代码实现初级版)

前言

通过一个小的登录功能模块案例,帮助大家了解MVP。最终实现一个结合Rxjava2,Retrofit 的MVP通用框架。代码放到github上。(如有错误之处,请在评论区指出,谢谢。如果感觉写的不错,请点赞,关注,谢谢。)

目录:

Android MVP-编程思想1(什么是MVC-MVP-MVVM模式?)
Android MVP-编程思想2(代码实现初级版)
Android MVP-编程思想3(内存泄露问题处理,基类封装,有没有必要再使用软引用?)
Android MVP-编程思想4(AOP思想-动态代理运用,反射创建M层实例对象)
Android MVP-编程思想5(如何处理多个P层的问题?)
Android MVP-编程思想6(依赖注入多个P层优化—注解,反射)
Android MVP-编程思想7(为什么使用代理类抽取通用方法而不是工具类?,基类BaseMvpFragment)

未完待续--------
Android MVP-编程思想8(集成Rxjava2,Retrofit)

MVP 实战
那么我们下面就要将这个类中的代码改写为 MVP 的写法,回顾上面提及的 MVP 架构的思想,它是将 View 层与 Model 层彻底隔离,意味着 View 和 Model 都不再持对方的引用,它们通过一个第三者 Presenter 来代理事物的传递,所以 Presenter 层会持有 Model 与 View 层的引用,这是第一步。

第二步,是将它们之间的联系抽象出来,以接口的方式相互调用,所以 Model 、View、Presenter 各自拥有自己的接口和抽象方法,所以这就会无形的多出了三个接口类,这也就是 MVP 的缺点之一。所以,为了较少的创建接口类,我们就给这三层接口定义了一个契约接口,把它们更加紧密的结合在一起,方法查看,例如代码这样写:参考谷歌官方mvp案例todo-mvp

下面我们以登录功能为例行了解 MVP 架构的代码写法。

第一步

首先我们参考谷歌todo-mvp 写一个契约类,定义交互行为。契约类的目的是把MVP的行为定义放在一起,方便阅读和维护

public class LoginContract {
    /**
     * V 定义View的行为,调用者是P
     */
    interface IView {
        //登录成功跳转到主界面
        void goToMainActivity();

        //请求网络显示等待框
        void showProgress(boolean isShow);

        //显示提示框-登录失败,或其他提示信息
        void showToast(String string);
    }

    /**
     * P(中转站和数据处理者) 定义View与Model的交互行为,调用者是V。P做中转
     */
    interface IPresenter {
        void onClickLogin(String username, String pwd);
    }

    /**
     * M 数据提供者
     */
    interface IModel {
        void getUserInfo(String username, String pwd, ICallBack callBack);
    }

}
第二步,定义MVP行为接口的实现类

辅助类ICallBack,用来回调http请求的数据

public interface ICallBack<T> {
    void success(T data);

    void error(String error);
}

M层的实现类LoginModel,提供数据,网络数据,本地数据

public class LoginModel implements LoginContract.IModel {
    @Override
    public void getUserInfo(String username, String pwd, final ICallBack callBack) {
        //todo 模拟 http请求
        Handler handler = new Handler();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                callBack.success("成功");
            }
        };
        handler.postDelayed(runnable, 2000);

    }
}

V层的实现类LoginActivity,控制视图显示,要调用P层接口,所以要持有P对象的引用

public class LoginActivity extends AppCompatActivity implements LoginContract.IView {
    LoginContract.IPresenter mPresenter;

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

        mPresenter = new LoginPresenter(this);
        findViewById(R.id.btn_login).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mPresenter.onClickLogin("xxx", "xxx");
            }
        });
    }

    @Override
    public void goToMainActivity() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                //todo 登录成功跳转到主界面
                Log.i("mvp_", "登录成功跳转到主界面");
            }
        });

    }

    @Override
    public void showProgress(boolean isShow) {
        if (isShow) {
            Log.i("mvp_", "显示等待框");
        } else {
            Log.i("mvp_", "隐藏等待框");
        }
    }

    @Override
    public void showToast(String str) {
        Toast.makeText(this, str, Toast.LENGTH_LONG).show();
    }
}

P层实现类LoginPresenter,是M和V交互的协调者,所以要持有M,V对象的引用
注意点:网络请求是耗时操作,我们 Presenter 层持有了 View 层的引用,也就是 Activity 的引用,在网络请求过程中,Activity被用户或者系统关闭,这时 View 相当于被摧毁了,如果不进行判断 View 引用是否为空,当数据返回时,就会造成空指针异常,所以每次都要进行判空才合理。

public class LoginPresenter implements LoginContract.IPresenter {
    private LoginContract.IModel mModel;
    private LoginContract.IView mView;

    public LoginPresenter(LoginContract.IView view) {
        this.mModel = new LoginModel();
        this.mView = view;
    }

    @Override
    public void onClickLogin(String username, String pwd) {
        mView.showProgress(true);
        mModel.getUserInfo(username, pwd, new ICallBack<String>() {
            @Override
            public void success(String data) {
                if (mView != null) {
                    mView.showToast("登录成功");
                    mView.showProgress(false);
                    mView.goToMainActivity();
                }
            }

            @Override
            public void error(String error) {
                if (mView != null) {
                    mView.showProgress(false);
                    mView.showToast("登录失败");
                }
            }
        });
    }
}

上面使用最简单的方式,演示了MVP的设计思想。目的是让大家理解,MVP模式是如何把业务逻辑,数据与V层进行分离的。再回想对比MVC是不是觉得MVP模式,职责分离的更清楚。

运行,点击登录按钮,打印日志如下:---------------------
2019-12-11 14:34:06.990 6376-6376/chongchong.wei.rx_retrofit_mvp I/mvp_: 显示等待框
2019-12-11 14:34:09.002 6376-6376/chongchong.wei.rx_retrofit_mvp I/mvp_: 隐藏等待框
2019-12-11 14:34:09.002 6376-6376/chongchong.wei.rx_retrofit_mvp I/mvp_: 登录成功跳转到主界面

当然上面的代码只是帮助大家理解MVP模式的思想,一些细节问题没有处理。下一节我们对代码进行优化,抽离,封装。

你可能感兴趣的:(architectural,thinking)