MVP架构

96
玄策
2018.02.24 03:00* 字数 353

目录

1)MVP简介
2)MVP实例


1)MVP简介

MVP模式将Activity中的业务逻辑全部剥离出来,Activity只做UI部分的处理,所有业务逻辑层由Presenter层去处理。

分层 说明
View Activity,Fragment,负责处理UI
Presenter 业务逻辑层,既能调用UI,又能请求数据源
Model 纯业务数据源的接口与实现

M层与V层无法直接通信,需要通过P层处理。

MVP

2)MVP实例

实现一个登录请求

假设我们来实现一个登录请求。


工程结构

-定义实体Bean

实体Bean
public class LoginReq {
    private String username;
    private String password;
    ...
}

public class LoginResponse {
    private String retcode;
    private String retinfo;
    private UserData userData;
    ...
}
public class UserData {
    private String name;
    private String age;
    ...
}

-Model层

Model层
  • Callback接口, 是Model给Presenter反馈数据信息的载体,需要在Callback中定义数据的各种反馈状态
//通过泛型T表示接受任意类型
public interface MvpCallback<T> {
    /**
     * 数据请求成功
     * @param data 请求到的数据
     */
    void onSuccess(T data);

    /**
     *  使用网络API接口请求方式时,虽然已经请求成功但是由
     *  于{@code msg}的原因无法正常返回数据。
     */
    void onFail(T data);

    /**
     * 请求数据失败,指在请求网络API接口请求方式时,出现无法联网、
     * 缺少权限,内存泄露等原因导致无法连接到请求数据源。
     */
    void onError();

    /**
     * 当请求数据结束时,无论请求结果是成功,失败或是抛出异常都会执行此方法给用户做处理,通常做网络
     * 请求时可以在此处隐藏“正在加载”的等待控件
     */
    void onComplete();
}
  • 登录业务接口,这里采用了ARouter-IProvider的服务依赖注入的方式去解耦服务,如不需要可不用继承IProvider
public interface ILoginBiz extends IProvider {

    //登录操作
    void login(LoginReq req, MvpCallback mvpCallback);

    //存储登录信息
    void saveUserdata(UserData userdata);
}
  • 登录业务实现,
@Route(path = "/service/login", name="登录服务")
public class LoginBiz implements ILoginBiz {

    @Override
    public void login(LoginReq req, final MvpCallback mvpCallback) {
        Map<String,String> param = new HashMap<String, String>();
        //调用公共组件库的OkHttpUtil进行网络API请求
        OkHttpUtil.sendRequestPost(param, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //模拟2秒休眠
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //回调onComplete
                mvpCallback.onComplete();
                //模拟response数据
                UserData userData = new UserData("涂高峰","18");
                LoginResponse loginResponse = new LoginResponse("000000","登录成功",userData);
                //回调onSuccess
                mvpCallback.onSuccess(loginResponse.getUserData());
            }
        });
    }

    @Override
    public void saveUserdata(UserData userdata) {

    }

    @Override
    public void init(Context context) {
    }
}

-View层,View接口是Activity层和Presenter层的中间层,它用于根据具体业务需要,为Presenter层提供调用Activity中具体UI操作的方法。

View层
  • IMvpView,抽象出的公共View
public interface IMvpView {

    /**
     * 显示正在加载view
     */
    void showLoading();

    /**
     * 关闭正在加载view
     */
    void hideLoading();

    /**
     * 显示提示
     * @param msg
     */
    void showToast(String msg);
}
  • ILoginView,登录业务View,继承了IMvpView。
public interface ILoginView extends IMvpView {

    /**
     * 登录请求成功提示
     */
    void loginSuccess(UserData userData);

    /**
     * 登录请求失败提示
     */
    void loginFail(String text);
}

-Presenter层,具体的业务逻辑处理Java类,不含任何Android-API操作,负责请求数据源,并对数据源反馈做处理。

Presenter层
  • MvpPresenter,抽象出公共的Presenter,
public class MvpPresenter<V extends IMvpView> {

    /**
     * 绑定的view
     */
    private V mvpView;

    /**
     * 绑定view,一般在初始化中调用该方法
     */
    public void attachView(V view){
        this.mvpView = view;
    }

    /**
     * 断开view,一般在onDestroy中调用
     * 对于Activity异常销毁导致mvpView空指针
     * 采用attachView和detachView,将view与activity生命周期绑定
     */
    public void detachView(){
        this.mvpView = null;
    }

    /**
     * 是否与View建立连接
     * 每次调用业务请求的时候都要出先调用方法检查是否与View建立连接
     */
    public boolean isViewAttached(){
        return this.mvpView != null;
    }

    /**
     * 获取连接的view
     */
    public V getView(){
        return this.mvpView;
    }

    /**
     * 获取连接的view名称
     */
    public String getViewName(){
        return this.mvpView.getClass().getSimpleName();
    }
}
  • LoginPresenter,登录业务Presenter,继承了MvpPresenter。
public class LoginPresenter extends MvpPresenter<ILoginView> {
    //依赖注入发现服务
    @Autowired(name = "/service/login")
    LoginBiz loginBiz;

    public LoginPresenter() {
//        this.loginBiz = new LoginBiz();
        //依赖注入
        ARouter.getInstance().inject(this);
    }

    public void login(LoginReq req){

        if (!isViewAttached()){
            //如果没有View引用就不加载数据
            return;
        }

        getView().showLoading();

        loginBiz.login(req, new MvpCallback() {
            @Override
            public void onSuccess(final Object data) {
                if (isViewAttached()){
                    MainLooper.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            getView().loginSuccess((UserData) data);
                        }
                    });
                }
            }

            @Override
            public void onFail(Object data) {

            }

            @Override
            public void onError() {

            }

            @Override
            public void onComplete() {
                if (isViewAttached()){
                    MainLooper.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            getView().hideLoading();
                        }
                    });
                }
            }
        });
    }
}

-Activity,登录业务Activity,实现了ILoginView

public class MainActivity extends AppCompatActivity implements ILoginView,View.OnClickListener{

    private LoginPresenter loginPresenter;
    private TextView txt;
    private ProgressBar progressBar;

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

        txt = findViewById(R.id.txt);
        progressBar = findViewById(R.id.progressBar);
        findViewById(R.id.success_btn).setOnClickListener(this);

        //初始化Presenter
        loginPresenter = new LoginPresenter();
        //绑定View引用
        loginPresenter.attachView(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //断开View引用
        loginPresenter.detachView();
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.success_btn:
                LoginReq loginReq = new LoginReq("tgf","123");
                loginPresenter.login(loginReq);
                break;
        }
    }

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

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

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

    @Override
    public void loginSuccess(UserData userData) {
        txt.setText("姓名: "+userData.getName() + "年龄"+ userData.getAge());
    }

    @Override
    public void loginFail(String text) {
    }
}

-其他工具类

public class MainLooper extends Handler {
    private static MainLooper instance = new MainLooper(Looper.getMainLooper());

    protected MainLooper(Looper looper) {
        super(looper);
    }

    public static MainLooper getInstance() {
        return instance;
    }

    public static void runOnUiThread(Runnable runnable) {
        if(Looper.getMainLooper().equals(Looper.myLooper())) {
            runnable.run();
        } else {
            instance.post(runnable);
        }
    }
}

参考资料

谷歌官方架构蓝图Android Architecture Blueprints
Android MVP架构搭建

Android-高级