先說下背景窄潭,市面上大部分公司在用的MVP MVVM等,google基于 MVP MVVM做了很多擴展架構(gòu)纫骑,在每個項目實際使用中都會有不同的擴展,接下來我會介紹一下基于這些思想的理解并設(shè)計的我們目前項目中使用的架構(gòu)
項目地址:android-mvp-architecture
項目架構(gòu)圖
實現(xiàn)思路
- 架構(gòu)主題服從mvp的思想,在model層做了一些更加細化的劃分,model層由各種原子化的usecase組合而成九孩,通過組合的方式使用先馆,以適應(yīng)復(fù)雜的ui需求,在個別耦合性比較強的業(yè)務(wù)之中躺彬,甚至可以考慮將這些usecase進行封裝煤墙,達到模塊化的目的梅惯。
- 整體架構(gòu)按照mvp和分層的思想設(shè)計,四層結(jié)構(gòu)仿野,自頂向下分別是:view視圖層铣减、presenter視圖控制層、usecase業(yè)務(wù)層和data repository數(shù)據(jù)層脚作。下層不依賴上層葫哗,以接口的方式為上層提供服務(wù)。
分層介紹
- View視圖層
負責(zé)用戶圖形界面的展示球涛,根據(jù)下層的數(shù)據(jù)劣针,驅(qū)動界面的顯示,比如按鈕的狀態(tài)亿扁,控件的顯示和隱藏等等捺典。
View是顯示數(shù)據(jù)(model)并且將用戶指令(events)傳送到presenter以便作用于那些數(shù)據(jù)的一個接口,通常將Activity或者Fragment作為View層。
- Presenter 視圖控制層
負責(zé)將下層拿到的數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)化為ui上面要使用的數(shù)據(jù)从祝,同時根據(jù)數(shù)據(jù)去控制上層ui界面的顯示襟己。
Presenter 是連接View層與Model層的橋梁并對業(yè)務(wù)邏輯進行處理,起到一個承上啟下的作用牍陌。負責(zé)從Model層獲得所需要的數(shù)據(jù)擎浴,進行一些適當?shù)奶幚砗蠼挥蒝iew層進行顯示。通過Presenter能很好的將View與Model進行隔離呐赡,使得View和Model之間不存在耦合退客,同時也將業(yè)務(wù)邏輯從View中抽離骏融,以及測試用例的編寫链嘀。
- Usecase 業(yè)務(wù)層
負責(zé)從下層讀取數(shù)據(jù),根據(jù)不同的業(yè)務(wù)選擇相關(guān)策略档玻,緩存讀取以及遠端讀取怀泊。在原則上
按照最小粒度設(shè)計,以便上層能夠更好的復(fù)用和組合多個業(yè)務(wù)误趴。
原子性就體現(xiàn)到了這一層上霹琼,不同的業(yè)務(wù)Task可以隨意組合,高復(fù)用凉当、擴展特性枣申,可以在presenter隨意組合使用
- Data repository 數(shù)據(jù)層
負責(zé)對接網(wǎng)絡(luò)和數(shù)據(jù)庫的相關(guān)邏輯,從遠端取數(shù)據(jù)以及更新數(shù)據(jù)庫緩存看杭。
代碼簡析
一忠藤、 首先看下幾個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;
}
@Override
public void onDestroy() {
super.onDestroy();
if (mPresenter != null) {
mPresenter.destroy();
}
}
}
通過使用泛型,傳入一個IRxPresenter 接口楼雹,在使用view的時候直接指定對應(yīng)的Presenter進行強綁定模孩,一個View只會對應(yīng)一個Presenter的原則尖阔,createPresenter()返回對應(yīng)的presenter,在整個view里面使用的是時候通過getPresenter()來獲取對象進行調(diào)度榨咐,在Activity生命周期走到onDestroy()時候會調(diào)用 mPresenter.destroy()介却,這時候可以在presenter里面的destroy()去cancel Task,這樣的好處就是退出activity時候會自動清理掉正在執(zhí)行還沒有回調(diào)的任務(wù)块茁。
- 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;
}
@Override
public V getView() {
return mView;
}
@Override
public void addSubscription(Subscription subscription) {
addSubscription(String.valueOf(subscription.hashCode()), subscription);
}
@Override
public void addSubscription(String tag, Subscription subscription) {
mSubscriptions.put(tag, subscription);
}
@Override
public void cancelSubscription(String tag) {
if (mSubscriptions.containsKey(tag)) {
mSubscriptions.get(tag).unsubscribe();
}
}
@Override
public void cancelAll() {
for (Subscription subscription : mSubscriptions.values()) {
subscription.unsubscribe();
}
}
@Override
public void destroy() {
cancelAll();
mSubscriptions = null;
}
}
在創(chuàng)建presenter的時候會通過泛型指定一個對應(yīng)的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這一層的核心類,主要功能是在創(chuàng)建Task的時候?qū)⒄埱髮嶓w和返回實體直接通過泛型定義好昌跌,當Task在執(zhí)行execute(Q values, UseCase.UseCaseCallback<P> callback) 方法時就自動進行觀察者和訂閱者進行綁定并傳入回調(diào)仰禀。
- RepositoryProvider
public class RepositoryProvider {
public static BankCardRepository getTasksRepository() {
return BankCardRepository.getInstance(BankCardRemoteDataSource.getInstance(),
BankCardLocalDataSource.getInstance());
}
}
RepositoryProvider這里可以將usecase進行業(yè)務(wù)層的劃分,每一個單例里面包含了這個業(yè)務(wù)對應(yīng)的接口蚕愤,可以看到
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分別實現(xiàn)了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;
}
@Override
public 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);
}
@Override
public 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);
}
@Override
public 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();
}
@Override
public 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();
}
@Override
public Observable<BaseListEntity<BankCardEntity>> delteAllBankCard() {
mRemoteDataSource.delteAllBankCard();
return mLocalDataSource.delteAllBankCard();
}
@Override
public Observable<BaseListEntity<BankCardEntity>> chageBankCardStatus(String cardId) {
mRemoteDataSource.chageBankCardStatus(cardId);
return mLocalDataSource.chageBankCardStatus(cardId);
}
}
這樣就很清晰了答恶,最終的調(diào)用者是在BankCardRepository這個類里面進行處理的,這樣一來我們就很容易擴展新的數(shù)據(jù)源(獲取數(shù)據(jù)的方式)萍诱,整個架構(gòu)涉及到的核心類基本介紹完了悬嗓。
四層架構(gòu)里面每一次都是面向接口編程,這為以后的擴展帶來了極大的好處裕坊。
總結(jié)
- 無論是MVP還是MVVM都只是形包竹,不要去被其外表所固定思維,真正用到具體項目要通過自己對整體的理解去擴展屬于自己的架構(gòu)籍凝,架構(gòu)都是需要根據(jù)業(yè)務(wù)形態(tài)去演進周瞎,目前這種架構(gòu)應(yīng)用在我們線上的項目里面。
- 為了更好的適應(yīng)業(yè)務(wù)的發(fā)展饵蒂,在之后的計劃之中声诸,app的設(shè)計會慢慢傾向于組件化的開發(fā)模式,各個模塊之間進行解耦退盯,使得代碼架構(gòu)更加清晰彼乌,降低項目的維護難度,也便于業(yè)務(wù)的擴展渊迁。