项目架构图
Picture
实现思路
架构主题服从mvp的思想,在model层做了一些更加细化的划分,model层由各种原子化的usecase组合而成,通过组合的方式使用,以适应复杂的ui需求,在个别耦合性比较强的业务之中,甚至可以考虑将这些usecase进行封装,达到模块化的目的。
整体架构按照mvp和分层的思想设计,四层结构,自顶向下分别是:view视图层、presenter视图控制层、usecase业务层和data repository数据层。下层不依赖上层,以接口的方式为上层提供服务。
分层介绍
View视图层
负责用户图形界面的展示,根据下层的数据,驱动界面的显示,比如按钮的状态,控件的显示和隐藏等等。
View是显示数据(model)并且将用户指令(events)传送到presenter以便作用于那些数据的一个接口,通常将Activity或者Fragment作为View层。
Presenter 视图控制层
负责将下层拿到的数据结构转化为ui上面要使用的数据,同时根据数据去控制上层ui界面的显示。
Model层也是数据层,负责数据的读取,在我们这里就是一系列的usecase,之所以进行一个细化,是为了满足各种复杂的ui设计,达到代码复用的目的
Presenter 是连接View层与Model层的桥梁并对业务逻辑进行处理,起到一个承上启下的作用。负责从Model层获得所需要的数据,进行一些适当的处理后交由View层进行显示。通过Presenter能很好的将View与Model进行隔离,使得View和Model之间不存在耦合,同时也将业务逻辑从View中抽离,以及测试用例的编写。
Usecase 业务层
负责从下层读取数据,根据不同的业务选择相关策略,缓存读取以及远端读取。在原则上
按照最小粒度设计,以便上层能够更好的复用和组合多个业务。
原子性就体现到了这一层上,不同的业务Task可以随意组合,高复用、扩展特性,可以在presenter随意组合使用
Data repository 数据层
负责对接网络和数据库的相关逻辑,从远端取数据以及更新数据库缓存。
代码简析
一、 首先看下几个Base类
BaseActivity
public class BaseActivity<P extends IRxPresenter> extends AppCompatActivity {private P mPresenter; @Override
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
mPresenter = createPresenter();
}protected P createPresenter() { return null;
}protected P getPresenter() { return mPresenter;
}@Overridepublic void onDestroy() { super.onDestroy(); if (mPresenter != null) {
mPresenter.destroy();
}
}
}通过使用泛型,传入一个IRxPresenter 接口,在使用view的时候直接指定对应的Presenter进行强绑定,一个View只会对应一个Presenter的原则,createPresenter()返回对应的presenter,在整个view里面使用的是时候通过getPresenter()来获取对象进行调度,在Activity生命周期走到onDestroy()时候会调用 mPresenter.destroy(),这时候可以在presenter里面的destroy()去cancel Task,这样的好处就是退出activity时候会自动清理掉正在执行还没有回调的任务。
BasePresenter:
public class BasePresenter<V extends IRxView> implements IRxPresenter<V> {private Map<String, Subscription> mSubscriptions = new HashMap<>();private V mView;public BasePresenter(V view) {
mView = view;
}@Overridepublic V getView() { return mView;
}@Overridepublic void addSubscription(Subscription subscription) {
addSubscription(String.valueOf(subscription.hashCode()), subscription);
}@Overridepublic void addSubscription(String tag, Subscription subscription) {
mSubscriptions.put(tag, subscription);
}@Overridepublic void cancelSubscription(String tag) { if (mSubscriptions.containsKey(tag)) {
mSubscriptions.get(tag).unsubscribe();
}
}@Overridepublic void cancelAll() { for (Subscription subscription : mSubscriptions.values()) {
subscription.unsubscribe();
}
}@Overridepublic void destroy() {
cancelAll();
mSubscriptions = null;
}}
在创建presenter的时候会通过泛型指定一个对应的IRxView,这就是上面说的View和Presenter的强绑定,其他几个方法就是简单的封装,方便presenter进行add和cancel的操作。
UseCase
public abstract class UseCase<Q extends UseCase.RequestValues, P extends IDataProtocol> {private boolean mStopAllWithFuture;private Q mRequestValues;private UseCaseCallback<P> mUseCaseCallback;private CompositeSubscription mCompositeSubscription = new CompositeSubscription();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;
}void run() {
Observable<P> task = buildUseCase(mRequestValues); if (task == null) { return;
}
mCompositeSubscription.add(task.compose(new ApplySchedulers<P>())
.subscribe(new EntitySubscriber<>(mUseCaseCallback)));
}protected abstract Observable<P> buildUseCase(Q requestValues);public final void execute(Q values, UseCase.UseCaseCallback<P> callback) { if (mStopAllWithFuture) { return;
}
setRequestValues(values);
setUseCaseCallback(callback);
run();
}/**
* Unsubscribes from current {@link Subscription}.
*/public void cancel() {
cancel(true);
}/**
* Unsubscribes from current {@link Subscription}.
*
* @param stopAllWithFuture stop the future tasks.
*/public void cancel(boolean stopAllWithFuture) {
mStopAllWithFuture = stopAllWithFuture;
mCompositeSubscription.clear();
}/**
* empty request.
*/public static class EmptyRequestValues extends BaseRequestValues {
}/**
* base request.
*/public abstract static class BaseRequestValues implements RequestValues {
}/**
* Data passed to a request.
*/public interface RequestValues {
}public interface UseCaseCallback<R> { void onSuccess(R response); void onError(int code, String error);
}}
UseCase这一层的核心类,主要功能是在创建Task的时候将请求实体和返回实体直接通过泛型定义好,当Task在执行execute(Q values, UseCase.UseCaseCallback<P> callback) 方法时就自动进行观察者和订阅者进行绑定并传入回调。
RepositoryProvider
public class RepositoryProvider {public static BankCardRepository getTasksRepository() { return BankCardRepository.getInstance(BankCardRemoteDataSource.getInstance(),
BankCardLocalDataSource.getInstance());
}
}RepositoryProvider这里可以将usecase进行业务层的划分,每一个单例里面包含了这个业务对应的接口,可以看到
BankCardRepository.getInstance(BankCardRemoteDataSource.getInstance(),
BankCardLocalDataSource.getInstance()初始化的时候需要传入local和reomte两个实例
public interface BankCardDataSource {
Observable<BaseListEntity<BankCardEntity>> addBankCard(BankCardEntity task);
Observable<BaseListEntity<BankCardEntity>> deleteBankCard(String taskId);
Observable<BaseListEntity<BankCardEntity>> getBankCardList();
Observable<BaseListEntity<BankCardEntity>> chageBankCardStatus(String taskId);
Observable<BaseListEntity<BankCardEntity>> delteAllBankCard();Observable<BankCardEntity> getBankCard(String taskId);}
可以看到BankCardLocalDataSource和BankCardRemoteDataSource分别实现了BankCardDataSource这个接口
public class BankCardRepository implements BankCardDataSource {private static BankCardRepository INSTANCE;private BankCardDataSource mRemoteDataSource;private BankCardDataSource mLocalDataSource;public BankCardRepository(BankCardDataSource remoteDataSource, BankCardDataSource localDataSource) { this.mRemoteDataSource = remoteDataSource; this.mLocalDataSource = localDataSource;
}public static BankCardRepository getInstance(BankCardDataSource remoteDataSource, BankCardDataSource localDataSource) { if (INSTANCE == null) {
BankCardRepository source = new BankCardRepository(remoteDataSource, localDataSource);
INSTANCE = source;
} return INSTANCE;
}@Overridepublic Observable<BaseListEntity<BankCardEntity>> addBankCard(BankCardEntity task) {
mRemoteDataSource.addBankCard(task).doOnNext(new Action1<BaseListEntity<BankCardEntity>>() { @Override
public void call(BaseListEntity<BankCardEntity> taskEntityBaseListEntity) { //TODO: save data to local
for (BankCardEntity entity : taskEntityBaseListEntity.list()) {
mLocalDataSource.addBankCard(entity);
}
}
}); return mLocalDataSource.addBankCard(task);
}@Overridepublic Observable<BaseListEntity<BankCardEntity>> deleteBankCard(String taskId) {
mRemoteDataSource.deleteBankCard(taskId).doOnNext(new Action1<BaseListEntity<BankCardEntity>>() { @Override
public void call(BaseListEntity<BankCardEntity> taskEntityBaseListEntity) { //TODO: save data to local
for (BankCardEntity entity : taskEntityBaseListEntity.list()) {
mLocalDataSource.addBankCard(entity);
}
}
}); return mLocalDataSource.deleteBankCard(taskId);
}@Overridepublic Observable<BaseListEntity<BankCardEntity>> getBankCardList() {
mRemoteDataSource.getBankCardList().doOnNext(new Action1<BaseListEntity<BankCardEntity>>() { @Override
public void call(BaseListEntity<BankCardEntity> taskEntityBaseListEntity) { //TODO: save data to local
for (BankCardEntity entity : taskEntityBaseListEntity.list()) {
mLocalDataSource.addBankCard(entity);
}
}
}); return mLocalDataSource.getBankCardList();
}@Overridepublic Observable<BankCardEntity> getBankCard(String cardId) {
Observable<BankCardEntity> remote = mRemoteDataSource.getBankCard(cardId).doOnNext(new Action1<BankCardEntity>() { @Override
public void call(BankCardEntity entity) {
mLocalDataSource.addBankCard(entity);
}
});
Observable<BankCardEntity> local = mLocalDataSource.getBankCard(cardId); return Observable.concat(remote, local).first();
}@Overridepublic Observable<BaseListEntity<BankCardEntity>> delteAllBankCard() {
mRemoteDataSource.delteAllBankCard(); return mLocalDataSource.delteAllBankCard();
}@Overridepublic Observable<BaseListEntity<BankCardEntity>> chageBankCardStatus(String cardId) {
mRemoteDataSource.chageBankCardStatus(cardId); return mLocalDataSource.chageBankCardStatus(cardId);
}}
这样就很清晰了,最终的调用者是在BankCardRepository这个类里面进行处理的,这样一来我们就很容易扩展新的数据源(获取数据的方式),整个架构涉及到的核心类基本介绍完了。
四层架构里面每一次都是面向接口编程,这为以后的扩展带来了极大的好处。
总结
无论是MVP还是MVVM都只是形,不要去被其外表所固定思维,真正用到具体项目要通过自己对整体的理解去扩展属于自己的架构,架构都是需要根据业务形态去演进,目前这种架构应用在我们线上的项目里面。
为了更好的适应业务的发展,在之后的计划之中,app的设计会慢慢倾向于组件化的开发模式,各个模块之间进行解耦,使得代码架构更加清晰,降低项目的维护难度,也便于业务的扩展。
作者:Android高级开发
链接:https://www.jianshu.com/p/b1d1d706eedc
共同學習,寫下你的評論
評論加載中...
作者其他優質文章
