Presenter層如何高度的複用

前提

這篇文章主要講的是在咱們的MVP CLEAN 涉及到PRESENTER層的架構,如何高度的複用咱們已經寫好的presenter,從而減小了不少代碼量。寫這篇文章也是本身的所思所想吧。有興趣的同窗能夠看看一下兩個連接關於Clean 和 mvp架構的。(若是文章中有錯誤或者結構問題歡迎指正)android

這篇文章的目的很簡單,如何高度抽象接口實現presenter複用。主要解決了UI頁面中多數據請求中如何複用已寫好的presenter。git

動機

咱們先來討論一下,當我把項目搭建成mvp架構的時候,是否是對於每個頁面的數據操做都要寫好相應的presenter view model,一樣你也能夠寫個Contract來完成view 和 presenter 的鏈接,這樣也能夠實現mvp的效果。github

  1. 若是對於單個頁面單個數據請求可能會少寫不少代碼量
  2. 對於單個頁面的多個數據操做,咱們的presenter會顯得很臃腫。
  3. 並且這些頁面(單頁面單數據請求,單頁面多數據請求)會有不少相同的數據操做內容。沒有獲得複用

這篇文章就是爲了解決這個問題數據庫

看結構圖

architecture.png
architecture.png

哈哈哈圖畫的可能比較簡單,但願不要介意,好吧咱們就從這個圖開始說吧。api

我這裏就簡單的說一下這個圖的結構吧,由於每個api(不管是網絡請求仍是數據庫操做)都是有用的,因此咱們能夠把每一個數據操做抽象成一個presenter 和 view 對於單數據操做的頁面能夠直接調用咱們寫好的preseter 對於多數據操做的能夠經過一個powerPresenter來完成對這個頁面的請求。bash

單數據操做的沒有什麼亮點,主要在於多數據操做如何完成view 層接口的回調和相應事件的回調。來完成這個powerPresenter網絡

base的完成

每一個人寫base可能都會有所不一樣,都是根據不一樣的業務來完成base的封裝,咱們若是想完成presenter 的高度複用base也是關鍵,咱們View層的Base Presenter層的Base Act層的Base都是息息相關的。最終完成咱們的目的,廢話很少說上代碼。架構

  • View Layer
public interface BaseView {

    void showLoading();

    void hideLoading();

    void showError(String message);

}複製代碼

這裏沒什麼內容也就是本身封裝的基礎業務。app

  • Presenter Layer
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中獲取便可。

  • 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 吧,老闆上代碼!!!!來了來了

view
public interface BannerView extends BaseView {
    void render(BannerBean bean);
}複製代碼
presenter
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 也不用管那麼多 就是一個網絡請求的封裝。

Act
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通用

  • 首先咱們看他的構造函數須要一個View 這個View 是繼承BaseView的咱們拿到這個View 幹嗎呢固然是爲了給數據操做完成後回參啊
  • 而後咱們又看到了這個方法很亮點requestPresenter裏面傳入一個數據,能夠知足多頁面多數據請求的操做。只要把咱們須要的請求經過以前寫好的presenter 傳入便可。而不須要在寫相應的presenter。從而達到複用。
  • 第三個亮點是他完美的吧view 關聯上了。因爲每一個數據請求都有對應的presenter 和view 這個類經過構造函數吧view 傳了進來而後經過遍歷數據吧view attachView上 完美的結合。
  • 一樣在destroy 的是完成了數據的解綁。
單頁面多數據操做如何完成

上代碼,簡單暴力 仍是以前的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 的複用,簡短的幾句代碼。

ending

又到了說再見的時候了,但願老鐵們看到以上文章有不對的地方和須要改善的地方指正一下。麼麼噠(其實這篇文章講的是一種思路,我這只是一種方法。你們徹底能夠根據本身的結構寫出一個比這讚的PowerPresenter)

相關文章
相關標籤/搜索