這篇文章主要講的是在咱們的MVP CLEAN 涉及到PRESENTER層的架構,如何高度的複用咱們已經寫好的presenter,從而減小了不少代碼量。寫這篇文章也是本身的所思所想吧。有興趣的同窗能夠看看一下兩個連接關於Clean 和 mvp架構的。(若是文章中有錯誤或者結構問題歡迎指正)android
這篇文章的目的很簡單,如何高度抽象接口實現presenter複用。主要解決了UI頁面中多數據請求中如何複用已寫好的presenter。git
咱們先來討論一下,當我把項目搭建成mvp架構的時候,是否是對於每個頁面的數據操做都要寫好相應的presenter view model,一樣你也能夠寫個Contract來完成view 和 presenter 的鏈接,這樣也能夠實現mvp的效果。github
這篇文章就是爲了解決這個問題數據庫
哈哈哈圖畫的可能比較簡單,但願不要介意,好吧咱們就從這個圖開始說吧。api
我這裏就簡單的說一下這個圖的結構吧,由於每個api(不管是網絡請求仍是數據庫操做)都是有用的,因此咱們能夠把每一個數據操做抽象成一個presenter 和 view 對於單數據操做的頁面能夠直接調用咱們寫好的preseter 對於多數據操做的能夠經過一個powerPresenter來完成對這個頁面的請求。bash
單數據操做的沒有什麼亮點,主要在於多數據操做如何完成view 層接口的回調和相應事件的回調。來完成這個powerPresenter網絡
每一個人寫base可能都會有所不一樣,都是根據不一樣的業務來完成base的封裝,咱們若是想完成presenter 的高度複用base也是關鍵,咱們View層的Base Presenter層的Base Act層的Base都是息息相關的。最終完成咱們的目的,廢話很少說上代碼。架構
public interface BaseView {
void showLoading();
void hideLoading();
void showError(String message);
}複製代碼
這裏沒什麼內容也就是本身封裝的基礎業務。app
public interface Presenter<T extends BaseView> {
void destroy();
void attachView(T view);
void detachView();
}複製代碼
這層的主要功能也能夠從接口上了解 就是綁定相應的View 和解綁防止內存泄漏(和大多數封裝的接口都差很少)。Presenter 沒有這麼簡單咱們又再次對這一層進行了二次包裝ide
public abstract class WrapperPresenter<T extends BaseView> implements Presenter<T> {
T mView;
@Override
public void attachView(T view) {
mView = view;
}
@Override
public void detachView() {
mView = null;
}
}複製代碼
這個包裝的目的很簡單就是省了每次寫presenter須要傳view進來直接從Activity中獲取便可。
public abstract class BaseMvpAct<T extends WrapperPresenter> extends AutoLayoutActivity implements BaseView {
protected T mPresenter;
private Unbinder bind;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(addContentView());
bind = ButterKnife.bind(this);
mPresenter = createP();
if (mPresenter != null) {
mPresenter.attachView(this);
}
initialize();
}
public abstract void initialize();
public abstract T createP();
public abstract int addContentView();
@Override
protected void onDestroy() {
super.onDestroy();
if (mPresenter != null) {
mPresenter.detachView();
}
if (bind != null) {
bind.unbind();
}
}
}複製代碼
這個就是BaseAct的基類,能夠經過泛型看到咱們要基礎這個Act須要傳WrapperPresenter的子類。咱們剛剛也看到了在WrapperPresenter裏面對view進行了綁定,而咱們在Base就完成了這個操做,因此咱們在實現一個api的presenter時就不必把view 當參數傳入了。
說了這麼多,沒看到複用啊,辣雞,哎呀小夥子不要急嘛,慢慢來。
有了這些Base咱們就能夠展示真正的技術了,寫好了這些base是否是開始瘋狂的擼代碼完成每一個數據操做的Presneter 和相應的view 啊。咱們就簡單的完成寫一個Presenter 和View 吧,老闆上代碼!!!!來了來了
public interface BannerView extends BaseView {
void render(BannerBean bean);
}複製代碼
public class BannerPresenter extends WrapperPresenter<BannerView> {
//你們不要想這個task啥東西就是網絡請求同樣
private BannerTask task;
public BannerPresenter() {
task = new BannerTask(new ApiIml(),new UIThread());
}
public void initialize(String type){
mView.showLoading();
this.getBanner(type);
}
public void getBanner(String type){
//執行網絡請求 回調到Observer 而後經過父類裏面的view回參
task.execute(new BannerObserver(), BannerTask.Params.forType(type));
}
private void BannerShow(BannerBean bean){
mView.render(bean);
}
private void BannerLoadFailed(Throwable ex){
mView.showError(ex.getMessage());
}
@Override
public void destroy() {
task.dispose();
}
private final class BannerObserver extends DefaultObserver<BannerBean>{
@Override
public void onNext(BannerBean bannerBean) {
//回參到view中
BannerPresenter.this.BannerShow(bannerBean);
}
@Override
public void onComplete() {
mView.hideLoading();
}
@Override
public void onError(Throwable exception) {
BannerPresenter.this.BannerLoadFailed(exception);
mView.showError(exception.getMessage());
}
}
}複製代碼
上面代碼已經寫了相應的註釋咱們就沒必要講太多了。對於那個task 也不用管那麼多 就是一個網絡請求的封裝。
public class BannerAct extends BaseMvpAct<BannerPresenter> implements BannerView {
@Override
public void showLoading() {
}
@Override
public void hideLoading() {
}
@Override
public void showError(String message) {
Log.i("cuieney", "showError: ");
}
@Override
public void render(BannerBean bean) {
Log.i("cuieney", "render: "+bean.toString());
}
@Override
public void initialize() {
mPresenter.initialize("banner");
}
@Override
public BannerPresenter createP() {
return new BannerPresenter();
}
@Override
public int addContentView() {
return 0;
}
}複製代碼
代碼很簡單,看看都懂,完成了上圖中的左半邊單頁面單數據請求。
終於回到主題了,如何完成presenter的複用 對於單頁面多數據請求,而不用寫多餘的presenter。
從上面的圖能夠看出來咱們input給了一些東西 (須要哪些數據操做的presenter),而後PowerPresenter output返回了相應的數據操做。很少說上代碼
public class PowerPresenter <T extends BaseView> extends WrapperPresenter<T>{
private T mView;
private List<Presenter> presenters = new ArrayList<>();
@SafeVarargs
public final <Q extends Presenter<T>> void requestPresenter(Q... cls){
for (Q cl : cls) {
cl.attachView(mView);
presenters.add(cl);
}
}
public PowerPresenter(T mView) {
this.mView = mView;
}
@Override
public void destroy() {
for (Presenter presenter : presenters) {
presenter.destroy();
}
}
}複製代碼
就問大家這個代碼簡不簡單,容不容易。並且他也是WrapperPresenter的子類,也就是說咱們BaseAct通用
上代碼,簡單暴力 仍是以前的BannerAct 修改爲單頁面多數據請求
public class BannerAct extends BaseMvpAct<PowerPresenter> implements BannerView {
private BannerPresenter bannerPresenter;
@Override
public void showLoading() {
}
@Override
public void hideLoading() {
}
@Override
public void showError(String message) {
Log.i("cuieney", "showError: ");
}
@Override
public void render(BannerBean bean) {
Log.i("cuieney", "render: "+bean.toString());
}
@Override
public void initialize() {
bannerPresenter.initialize("dsds");
}
@Override
public PowerPresenter createP() {
PowerPresenter presenter = new PowerPresenter<>(this);
bannerPresenter = new BannerPresenter();
····(這裏你能夠添加任何你須要的presenter)····
presenter.requestPresenter(bannerPresenter);
return presenter;
}
@Override
public int addContentView() {
return 0;
}
}複製代碼
經過上面代碼能夠看到,咱們在實現了父類裏面的createP方法,而後經過建立PowerPresenter 而後把咱們須要的BannerPresenter網絡請求加到了requestPresenter請求中 達到了BannerPresenter 的複用,簡短的幾句代碼。
又到了說再見的時候了,但願老鐵們看到以上文章有不對的地方和須要改善的地方指正一下。麼麼噠(其實這篇文章講的是一種思路,我這只是一種方法。你們徹底能夠根據本身的結構寫出一個比這讚的PowerPresenter)