Android MVP 架構

本Demo使用 Okhttp3、Retrofit2诅岩、Rxjava2 ,使用AutoDispose解決RxJava內存泄漏
Github:
https://github.com/RookieExaminer/MvpDemo

什么是MVP芳撒,為什么要用MVP萨西?
網上介紹MVP的很多汹来,百度一下你就知道欧穴,至于為什么要用MVP洼畅,當然是由于它的優(yōu)勢了:
1.代碼簡潔
此處的簡潔是邏輯的簡潔,而不是代碼本身 舉個栗子

image.png

比如購物車界面霍殴,有很多請求網絡的地方:獲取購物車商品列表窍蓝、購物車商品的刪除、購物車商品的購買等等繁成, 這么多網絡請求吓笙,如果都寫在一個Activity,而且還有大量邏輯判斷巾腕,那這個Activity的行數~ 看著就讓人頭痛面睛, 即便寫了注釋,維護起來也是比較麻煩的
2.降低耦合尊搬,方便維護
MVP的使用叁鉴,使Activity中的網絡請求剝離出來 成為model、presenter佛寿,model只負責網絡的請求幌墓、pesenter負責處理請求網絡后的數據處理:加載中 成功 or 失敗 取消加載;最后View進行界面的展示


image.png

image.png

Start 看圖:

image.png

嗯哼冀泻? 不是 Model常侣、Presenter、View這三個 么弹渔,怎么又多出來個Contract胳施,這又是什么鬼?
這就涉及到MVP的缺點了肢专,正所謂舞肆,金無足赤,人無完人博杖,MVP既然有優(yōu)點當然也有它的缺點了
MVP在實現代碼簡潔的同時椿胯,額外增加了大量的接口、類剃根,不方便進行管理哩盲,于是Contract就登場了。

Contract 百度翻譯 : 合同;契約;協議
Contract 如其名跟继,是一個契約种冬,將Model镣丑、View舔糖、Presenter 進行約束管理,方便后期類的查找莺匠、維護金吗。

下面演示下登陸的MVP實現方式:
(示例代碼由開發(fā)項目中剝離到Demo中,登陸接口使用的是玩安卓的登陸API:http://www.wanandroid.com/blog/show/2

首先,創(chuàng)建一個登陸的Contract:

public interface MainContract {
    interface Model { }

    interface View extends BaseView { }

    interface Presenter { }
}
其次創(chuàng)建Presenter摇庙、Model旱物、View 對應Contract中的接口;
public class MainPresenter implements  MainContract.Presenter{} 
public class MainModel implements MainContract.Model{}
public class MainActivity  implements MainContract.View {}

完整的Contract:

public interface MainContract {
    interface Model {
        Flowable<BaseObjectBean<LoginBean>> login(String username, String password);
    }

    interface View extends BaseView {
        @Override
        void showLoading();

        @Override
        void hideLoading();

        @Override
        void onError(Throwable throwable);

        void onSuccess(BaseObjectBean<LoginBean> bean);
    }

    interface Presenter {
        /**
         * 登陸
         *
         * @param username
         * @param password
         */
        void login(String username, String password);
    }
}

在MainContract 中
Model接口 創(chuàng)建對應的聯網請求的方法卫袒,將Presenter提交的字段放到聯網請求中宵呛,發(fā)送給服務器
View 接口 創(chuàng)建在界面上顯示加載中、取消加載以及登陸成功夕凝、失敗的方法
Presenter 接口 創(chuàng)建 登陸的方法宝穗,以及需要提交的字段 (username、password)

MainModel的完整代碼:

public class MainModel  implements MainContract.Model {
    @Override
    public Flowable<BaseObjectBean<LoginBean>> login(String username, String password) {
        return RetrofitClient.getInstance().getApi().login(username,password);
    }
}

Model類實現MainContract.Model 接口中的 login(String username, String password)方法码秉,將username逮矛、password放在聯網請求中,進行請求服務器转砖。

MainView 的完整代碼:

public class MainActivity extends BaseMvpActivity<MainPresenter> implements MainContract.View {

    @BindView(R.id.et_username_login)
    TextInputEditText etUsernameLogin;
    @BindView(R.id.et_password_login)
    TextInputEditText etPasswordLogin;

    @Override
    public int getLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    public void initView() {
        mPresenter = new MainPresenter();
        mPresenter.attachView(this);
    }

    /**
     * @return 帳號
     */
    private String getUsername() {
        return etUsernameLogin.getText().toString().trim();
    }

    /**
     * @return 密碼
     */
    private String getPassword() {
        return etPasswordLogin.getText().toString().trim();
    }

    @Override
    public void onSuccess(BaseObjectBean bean) {

        Toast.makeText(this, bean.getErrorMsg(), Toast.LENGTH_SHORT).show();

    }

    @Override
    public void showLoading() {
        ProgressDialog.getInstance().show(this);
    }

    @Override
    public void hideLoading() {
        ProgressDialog.getInstance().dismiss();
    }

    @Override
    public void onError(Throwable throwable) {

    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // TODO: add setContentView(...) invocation
        ButterKnife.bind(this);
    }

    @OnClick(R.id.btn_signin_login)
    public void onViewClicked() {
        if (getUsername().isEmpty() || getPassword().isEmpty()) {
            Toast.makeText(this, "帳號密碼不能為空", Toast.LENGTH_SHORT).show();
            return;
        }
        mPresenter.login(getUsername(), getPassword());
    }
}

MainActivity 中實現 MainContract.View中的方法 须鼎,在實現的方法中,進行進度條加載府蔗、和登陸成功or失敗的UI的展示:

        @Override
        void showLoading();

        @Override
        void hideLoading();

        @Override
        void onError(Throwable throwable);

        void onSuccess(BaseObjectBean<LoginBean> bean);

MainPresenter 的完整代碼:

public class MainPresenter extends BasePresenter<MainContract.View> implements MainContract.Presenter {

    private MainContract.Model model;

    public MainPresenter() {
        model = new MainModel();
    }

    @Override
    public void login(String username, String password) {
        if (!isViewAttached()) {
            return;
        }
        mView.showLoading();
        model.login(username, password)
                .compose(RxScheduler.<BaseObjectBean<LoginBean>>Flo_io_main())
                .as(mView.<BaseObjectBean<LoginBean>>bindAutoDispose())
                .subscribe(new Consumer<BaseObjectBean<LoginBean>>() {
                    @Override
                    public void accept(BaseObjectBean<LoginBean> bean) throws Exception {
                        mView.onSuccess(bean);
                        mView.hideLoading();
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        mView.onError(throwable);
                        mView.hideLoading();
                    }
                });
    }
}

MainPresenter 實現MainContract.Presenter 接口中的 login(String username, String password) 方法

實例化Model晋控,在MainPresenter login(String username, String password)方法中,調用model的網絡請求姓赤,將username糖荒、password放在model的login()方法中,進行請求服務器模捂。
請求服務器前 使用MainContract.View中的 mView.showLoading()方法捶朵,進行顯示加載中;在成功失敗的回調中狂男,使用對應的方法综看,以及取消加載。

其中BasePresenter岖食、BaseView 是對Presenter以及View進行的封裝

BaseView類:

public interface BaseView {

    /**
     * 顯示加載中
     */
    void showLoading();

    /**
     * 隱藏加載
     */
    void hideLoading();

    /**
     * 數據獲取失敗
     * @param throwable
     */
    void onError(Throwable throwable);

    /**
     * 綁定Android生命周期 防止RxJava內存泄漏
     *
     * @param <T>
     * @return
     */
    <T> AutoDisposeConverter<T> bindAutoDispose();

}

至于為什么不把onSuccess()方法也封裝红碑,是因為請求網絡,服務器返回的值是不一樣的泡垃,在Contract > View接口中根據bean類設置onSuccess()

BasePresenter類:

public class BasePresenter<V extends BaseView> {
    protected V mView;


    /**
     * 綁定view析珊,一般在初始化中調用該方法
     *
     * @param view view
     */
    public void attachView(V view) {
        this.mView = view;
    }

    /**
     * 解除綁定view,一般在onDestroy中調用
     */

    public void detachView() {
        this.mView = null;
    }

    /**
     * View是否綁定
     *
     * @return
     */
    public boolean isViewAttached() {
        return mView != null;
    }


}

時間有限蔑穴,暫時就先這樣忠寻,具體可下載Demo查看 ↓

本Demo: https://github.com/RookieExaminer/MvpDemo
MVP快速生成類的插件: https://github.com/githubwing/MVPHelper

參考:
Android MVP架構搭建:
http://www.jcodecraeer.com/a/anzhuokaifa/2017/1020/8625.html?1508484926
Android架構中添加AutoDispose解決RxJava內存泄漏:
http://www.reibang.com/p/8490d9383ba5

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市存和,隨后出現的幾起案子奕剃,更是在濱河造成了極大的恐慌衷旅,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纵朋,死亡現場離奇詭異柿顶,居然都是意外死亡,警方通過查閱死者的電腦和手機操软,發(fā)現死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門嘁锯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人聂薪,你說我怎么就攤上這事猪钮。” “怎么了胆建?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵烤低,是天一觀的道長。 經常有香客問我笆载,道長扑馁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任凉驻,我火速辦了婚禮腻要,結果婚禮上,老公的妹妹穿的比我還像新娘涝登。我一直安慰自己雄家,他們只是感情好,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布胀滚。 她就那樣靜靜地躺著趟济,像睡著了一般。 火紅的嫁衣襯著肌膚如雪咽笼。 梳的紋絲不亂的頭發(fā)上顷编,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機與錄音剑刑,去河邊找鬼媳纬。 笑死,一個胖子當著我的面吹牛施掏,可吹牛的內容都是我干的钮惠。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼七芭,長吁一口氣:“原來是場噩夢啊……” “哼素挽!你這毒婦竟也來了?” 一聲冷哼從身側響起抖苦,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤毁菱,失蹤者是張志新(化名)和其女友劉穎米死,沒想到半個月后锌历,有當地人在樹林里發(fā)現了一具尸體贮庞,經...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年究西,在試婚紗的時候發(fā)現自己被綠了窗慎。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡卤材,死狀恐怖遮斥,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情扇丛,我是刑警寧澤术吗,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站帆精,受9級特大地震影響较屿,放射性物質發(fā)生泄漏。R本人自食惡果不足惜卓练,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一隘蝎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧襟企,春花似錦嘱么、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蔚龙,卻和暖如春拴测,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背府蛇。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工集索, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人汇跨。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓务荆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親穷遂。 傳聞我的和親對象是個殘疾皇子函匕,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現蚪黑,斷路器盅惜,智...
    卡卡羅2017閱讀 134,651評論 18 139
  • 從MVP開發(fā)模式至今中剩,其實已經過了好久;很多開發(fā)者也已經輕車熟路的運用到了項目中抒寂,本來猶豫要不要寫這篇文章结啼,后來發(fā)...
    DevCW閱讀 4,201評論 31 93
  • 最近稍微了解了下MVP架構模式郊愧,這篇文章寫得不錯,轉過來mark下:原博客原地址:http://www.jians...
    Stan_Z閱讀 1,186評論 0 8
  • 引言 目前Android開發(fā)比較流行的是MVP開發(fā)架構井佑,與MVC不同的是把Activity属铁、Fragment等頁面...
    OzanShareing閱讀 8,290評論 3 21
  • 納粹德國在 1942 年研發(fā)的超重型戰(zhàn)車, 延續(xù)動物園稱號的七號戰(zhàn)車---獅躬翁, 有 90噸的重獅與 76噸的輕獅二...
    Alice_v閱讀 378評論 0 0