手把手寫一個Clean(+mvp+rxjava)架構的Demo
作者:點先生 時間:2018.12.26
前言
前段時間在天星群中有朋友說到了clean架構。剛好在最近的專案裡面我在搭建框架的時候用到了clean,所以在這裡就把搭建過程在這裡描述一下。Demo在文章末尾。本文側重於clean的搭建,mvp+rxjava的部分,不做介紹。
(咦?我聽到有人在問什麼是天星群。既然你誠心誠意的發問了,那我就給你們透露一下。天星是一群Android開發者閒的沒事幹搞的一個部落格團隊,這是團隊部落格地址:點這裡,這個是粉絲qq群:557247785。歡迎妹子和女裝大佬們!)
CleanArchitecture
mvp和rxjava基本是現在開發標配,有很多寫的比較好的文章。對mvp和rxjava比較熟的同學可以繼續往下看了。還不熟的同學可以看看
Clean是一種架構的思想,跟MVP一樣,解耦就完事兒了。(那一群解耦狂魔,你根本不知道他們究竟想怎樣!)關於clean框架的解析很多,我不再贅述,畢竟本文是手把手寫一個Demo。
Clean思想由Uncle Bob提出的,英文不錯的看這個 The Clean Code Blog
Google爸爸寫的Demo可以作為參考todo‑mvp‑clean
android10的文章圖解多,比較容易理解,推薦!Android-CleanArchitecture
中文版可以看看來自谷歌清潔工的Clean架構探討,我覺得講的很好。
按慣例這裡該有一張表情包,但是我沒有找到可以皮的理由,所以,算了。
手把手寫mvp+rxjava+clean
現在來模擬一個登陸功能。mvp是clean架構的基礎,我們先把mvp+rxjava的框架給弄好。我的專案結構是這樣的。
分為了data,domain,presentation 三層。分別對應clean的三層。 data層和presentation層大家應該都比較熟悉,就是一些mvp的東西。 那這個domain layout是幹嘛的?
業務邏輯,use case實現的地方 以前在mvp架構的時候,我們會說。我要是不知道這個app能幹嘛,看一眼presenter的介面就知道了。那在clean裡面就可以說。我要是不知道這app能幹嘛,看一眼domain層就知道了。
usecase更加簡化了presenter裡面的程式碼以前presenter裡面會呼叫data層的東西,現在presenter只管負責的usecase。程式碼量大大的減少。
usecase純java程式碼,不含androd依賴
那usecase是幹嘛的? 看看google官方todo‑mvp‑clean裡面Usecase在幹嘛,又是如何呼叫的。
Google clean demo核心解析
UseCase
- 抽象類
- 傳進來了請求引數Q,相應引數P
- 有一個回撥介面UseCaseCallback
- set幾個屬性的方法。
- run(): 帶著Q執行usecase
UseCase實現類
- 建構函式傳入了repository
- P,Q兩個靜態內部類
- executeUseCase():通過傳入的repository執行資料請求的操作,並執行回撥函式。
UseCaseHandler
- 統一管理Usecase的execute方法。
- 通過execute方法把需要處理的UseCase<T, R>、請求引數T、回撥介面UseCase.UseCaseCallback進行繫結,方便請求與回撥。
presenter裡的使用
使用哪個方法的時候,就呼叫傳入哪個usecase,和請求需要的引數,和相應的回撥介面。
我們繼續手把手
UseCaseHandler主要作用就是統一管理,回撥直觀。 當我們把rxjava2加入進來之後,UseCaseHandler就沒有存在的意義了。 去掉handler,不需要繫結這雜七雜八的東西之後,usecase可以簡化了。所以我的BaseUseCase是這樣的
MyUseCase
public abstract class BaseUseCase<P, Q> {
private final Scheduler observerThread;
private final Scheduler subcriberThread;
private final CompositeDisposable disposables;
public BaseUseCase(Scheduler observerThread, Scheduler subcriberThread) {
this.observerThread = observerThread;
this.subcriberThread = subcriberThread;
this.disposables = new CompositeDisposable();
}
protected abstract Observable<Q> buildUseCaseObservable(P request);
public void execute(DisposableObserver<Q> observer, P request) {
Preconditions.checkNotNull(observer);
final Observable<Q> observable = this.buildUseCaseObservable(request)
.subscribeOn(observerThread)
.observeOn(subcriberThread);
addDisposable(observable.subscribeWith(observer));
}
public void dispose() {
if (!disposables.isDisposed()) {
disposables.dispose();
}
}
public void addDisposable(Disposable disposable) {
Preconditions.checkNotNull(disposable);
Preconditions.checkNotNull(disposables);
disposables.add(disposable);
}
}
複製程式碼
跟google的demo做了一樣的事,不過加了CompositeDisposable統一管理而已。
MyUseCase實現類
public class LoginUseCase extends BaseUseCase<LoginUseCase.RequestValue, User> {
private final Repository repository;
public LoginUseCase(Scheduler observerThread, Scheduler subcriberThread, Repository repository) {
super(observerThread, subcriberThread);
this.repository = repository;
}
@Override
protected Observable<User> buildUseCaseObservable(RequestValue request) {
return repository.getUser(request.account, request.password);
}
public static final class RequestValue {
final String account;
final String password;
public RequestValue(String account, String password) {
this.account = Preconditions.checkNotNull(account);
this.password = Preconditions.checkNotNull(password);
}
}
}
複製程式碼
跟google的demo差不多基本一致,把ResponseValue改成了返回的實體類。
MyPresenter裡的使用
@Override
public void login(String account, String password) {
loginUseCase.execute(new LoginObserver(), new LoginUseCase.RequestValue(account, password));
}
private final class LoginObserver extends DisposableObserver<User> {
@Override
public void onNext(User user) { loginUseCase.saveUser(user); }
@Override
public void onError(Throwable e) { }
@Override
public void onComplete() { }
}
複製程式碼
其他
/*ButterKnife*/
implementation 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
/*GreenDao*/
implementation 'org.greenrobot:greendao:3.2.2'
/*Retrofit*/
implementation 'com.squareup.retrofit2:retrofit:2.0.2'
implementation 'com.squareup.okhttp3:okhttp:3.1.2'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
implementation 'com.squareup.okhttp3:okhttp-urlconnection:3.5.0'
/*Rxjava2*/
implementation 'io.reactivex.rxjava2:rxjava:2.1.3'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
複製程式碼
全部原始碼在這裡:github.com/GuitarDian/…