这一篇我们来讲下针对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就讲完了,代码在这里
网友评论