Android MVP扩展

作者: 2ece9f02c806 | 来源:发表于2016-08-29 16:05 被阅读1226次

上一篇:Android MVP高级

这一篇我们来讲下针对Android MVP的一个扩展,其实就是将M-V-P中的M和P之间加一层:UseCase
这个就是大名顶顶的Android Clean Architecture,什么是Android Clean Architecture呢,这个网上很多,一查便知。
使用Android Clean Architecture的好处是

  • 代码复用性更高
  • 更易于测试
  • 耦合度更小

下面用几张图简单说下什么是Android Clean Architecture:

Paste_Image.png

上面这张图清晰的表明的Android Clean Architecture的思想:
它把整个应用从外到内分为四层

  • 最底层的是Entities也就是Model层,只负责取数据,不管是从网络还是从本地
  • 第二层是UseCase层,它负责把Model层获取来的数据进行处理,然后把处理结果传给上层
  • 第三层是Presenter层,它负责联通UseCase层与最外围的UI层
  • 最外层是UI层,负责UI处理逻辑

下面这张图是googlesample的Android Clean Architecture结构

Paste_Image.png

分了三层:

  • DataLayer ,也就是Model层
  • DomainLayer ,也就是UseCase层
  • PresentationLayer,也就是Presenter+UI层

个人觉得google这个分层方式比较好,后面我就以这三层来讲。
下面引用这篇文章内容说明下 简单的 Android Clean Architecture 实现

DataLayer

最底层,完全不知道有 DomainLayer , PresentationLayer 的存在,它的主要职责是:
1、从网络获取数据,向网络提交数据,总之就是和网络打交道。
2、从本地DB,shareprefence等等,内存等,总之就是本地获取数据,缓存数据,总之就是和本地数据打交道的。

DomainLayer

中间层,他完全不知道有一个 PresentationLayer 存在,他只知道,有DataLayer,它的主要职责是:
控制 DataLayer 对数据做 增删改查

PresentationLayer

最上层,他知道 DomainLayer,注意他并不知道DataLayer,它的职责是:
通知 DomainLayer 有活干了,根据 DomainLayer 反馈变化界面

三层结构每一层都只知道自己的上一层,就好像一个公司结构一样,老板指挥管理层,管理层指挥基层,老板不直接指挥基层

好了,Android Clean Architecture就介绍到这里,下面讲实现:
我们在上一篇 Android MVP高级 源码基础上改
选加一个BaseUseCase:

public abstract class BaseUseCase<Q extends BaseUseCase.RequestValues, P extends BaseUseCase.ResponseValue> {

    private Q mRequestValues;

    private UseCaseCallback<P> mUseCaseCallback;

    public void setRequestValues(Q requestValues) {
        mRequestValues = requestValues;
    }

    public Q getRequestValues() {
        return mRequestValues;
    }

    public UseCaseCallback<P> getUseCaseCallback() {
        return mUseCaseCallback;
    }

    public void setUseCaseCallback(UseCaseCallback<P> useCaseCallback) {
        mUseCaseCallback = useCaseCallback;
    }

    public void run() {
        executeUseCase(mRequestValues);
    }

    /**
     * 执行该用例
     *
     * @param requestValues 用例输入
     */
    public abstract void executeUseCase(Q requestValues);

    /**
     * 用例的输入(请求参数)
     */
    public interface RequestValues {
    }

    /**
     * 用例的输出(返回结果)
     */
    public interface ResponseValue {
    }

    /**
     * 用例回调
     *
     * @param <R>
     */
    public interface UseCaseCallback<R> {
        void onSuccess(R response);

        void onError(String errorCode, Object... errorMsg);
    }
}

这是一个虚类,是所有用例的父类,子类需要实现executeUseCase方法。
BaseUseCase类里有三个接口:

  • RequestValues:代表用例的输入数据,所有用例输入都要实现此接口
  • ResponseValue :代表用例的输出数据,所有用例输出都要实现此接口
  • UseCaseCallback :是用例的回调,用于向外层反馈用例执行结果

每个用例都要传入RequestValues以及UseCaseCallback,当用例执行的时候使用RequestValues向model层取数据,然后将数据封装成ResponseValue,通过UseCaseCallback返回给调用者。

接下来写一个LoginCase,继承自BaseUseCase

public class LoginCase extends BaseUseCase<LoginCase.RequestValues, LoginCase.ResponseValue> {

    private final IUserModel userModel;

    public LoginCase(IUserModel userModel) {
        this.userModel = userModel;
    }

    /**
     * 执行该用例
     *
     * @param requestValues 用例输入
     */
    @Override
    public void executeUseCase(RequestValues requestValues) {
        String username = requestValues.getUsername();
        String password = requestValues.getPassword();
        userModel.login(username, password, new Callback() {
            @Override
            public void onSuccess() {
                getUseCaseCallback().onSuccess(new ResponseValue());
            }

            @Override
            public void onFailure(String errorMsg) {
                getUseCaseCallback().onError("1001", errorMsg);
            }
        });
    }

    public static final class RequestValues implements BaseUseCase.RequestValues {
        private final String username;
        private final String password;

        public RequestValues(@NonNull String username, @NonNull String password) {
            this.username = username;
            this.password = password;
        }

        public String getUsername() {
            return username;
        }

        public String getPassword() {
            return password;
        }
    }

    public static final class ResponseValue implements BaseUseCase.ResponseValue {
    }
}

LoginCase包含两个类RequestValues,ResponseValue ,分别实现了BaseUseCase中的RequestValues,ResponseValue 接口
LoginCase构造方法中传入了IUserModel参数,这里就把DataLayer引进来了。
LoginCase实现了executeUseCase方法,这里从RequestValues获取用户名和密码,然后调用userModel的login方法,发出登录请求,之后通过getUseCaseCallback获取回调,把结果通过回调返回给调用者(Presenter)。
到这里一个登录的用例就写好了,然后是Presenter的改造

public class LoginPresenter extends BasePresenter<ILoginView> implements ILoginPresenter {

    private final LoginCase loginCase;

    public LoginPresenter(LoginCase loginCase) {
        this.loginCase = loginCase;
    }


    /**
     * 登录
     */
    @Override
    public void login() {
        checkViewAttached();
        getMvpView().showLoading("登录中...");
        LoginCase.RequestValues requestValues = new LoginCase.RequestValues(getMvpView().getUsername(), getMvpView().getPassword());
        loginCase.setRequestValues(requestValues);
        loginCase.setUseCaseCallback(new BaseUseCase.UseCaseCallback<LoginCase.ResponseValue>() {
            @Override
            public void onSuccess(LoginCase.ResponseValue response) {
                if (isViewAttached()) {
                    getMvpView().hideLoading();
                    getMvpView().showResult("登录成功");
                }
            }

            @Override
            public void onError(String errorCode, Object... errorMsg) {
                if (isViewAttached()) {
                    getMvpView().hideLoading();
                    getMvpView().showError(errorMsg.toString());
                }
            }
        });
        loginCase.run();
    }
}

LoginPresenter构造方法传入了参数LoginCase, 调用login方法时候往loginCase中传入RequestValues和UseCaseCallback,然的调用loginCase的run方法就OK了,这样一来Presenter就变得很干净了。

接着我们写一个UseCaseManager用来管理UseCase的实例化(以便切换分支操作参考我这篇文章:Android Studio Flavors的妙用

public class UseCaseManager {
    public static LoginCase provideLoginCase() {
        return new LoginCase(ModelManager.provideUserModel());
    }
}

最后修改下LoginActivity的onCreateLoader方法

    @Override
    public Loader<LoginPresenter> onCreateLoader(int id, Bundle args) {
        return new PresenterLoader(this, new PresenterFactory<LoginPresenter>() {
            @Override
            public LoginPresenter create() {
                return new LoginPresenter(UseCaseManager.provideLoginCase());
            }
        });
    }

到此Android MVP+Android Clean Architecture就讲完了,代码在这里

相关文章

网友评论

    本文标题:Android MVP扩展

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