Android MVP的簡單實現(xiàn)

一個好的好的設(shè)計模式可以幫我們很好的管理我們的代碼褒脯,也會方便于我們的后期的擴展缆毁。特別是針對我們這樣的新手,學(xué)好一個好的代碼管理是很有必要的颁督。所以今天浇雹,和大家一起學(xué)習(xí)一下MVP模式。

一吠裆、MVP設(shè)計模式概述

什么是MVP設(shè)計模式

MVP,分別是Model-View-Presenter,即模型-視圖-提出者硫痰。
Model:模型,實現(xiàn)業(yè)務(wù)邏輯和實例生成非春。
View:視圖缓屠,對應(yīng)的界面布局,以及界面布局的方法储耐。
Presenter:一個活動中滨溉,主要的業(yè)務(wù)交互,作為view和model的中間傳達者闽撤。

什么是MVC設(shè)計模式

MVP脯颜,分別是Model-View-Presenter,即模型-視圖-控制器。
Model:模型闸餐,實現(xiàn)業(yè)務(wù)邏輯和實例生成矾芙。
View:視圖,對應(yīng)的界面布局蠕啄,以及界面布局的方法歼跟。
Controllor:作為頁面的控制器格遭,響應(yīng)view的交互,對應(yīng)于Android中的Activity

對比

這么說可能不是很清晰拒迅,我們用兩張圖片來描述一下。


MVP與MVC對比

但是在Android我們的可以知道硬梁,其實Avtivity不僅要處理view的呈現(xiàn)胞得,還要負責(zé)處理頁面的業(yè)務(wù)邏輯,顯得Activity不僅像view阶剑,又像controllor的結(jié)合體牧愁,導(dǎo)致Acitivity整體臃腫,超過1000行都是常事猪半。

所以,為了更好的解耦這樣的情況沽甥,讓Activity更好的只關(guān)心頁面的呈現(xiàn)俐填,將主要的業(yè)務(wù)交互放置在presenter中實現(xiàn),讓Presenter作為view與model的中間傳遞者盏檐。減少Activity的體積驶悟。降低耦合度。

在MVP模式中硫豆,我們要做到笼呆,view層和model不能直接通信,要想通信汗茄,必須通過Persenter這一中間件铭若。并且递览,view瞳腌,model,presenter都是接口儿捧,之間的通訊也都是通過接口實現(xiàn)的吵冒。

二、 MVP的簡單實現(xiàn)

接下來我們通過一個基礎(chǔ)的實例亿汞,讓我們來實現(xiàn)一個簡單的MVP模式的登錄界面揪阿。從實例的角度,我們來分析一個具體的MVP模式吴裤∧缃。看看他是怎樣實現(xiàn)解耦,以及明顯的內(nèi)容劃分剖膳。

Model層:

model層是用來實現(xiàn)某一層里面的業(yè)務(wù)邏輯岭辣。
那么,在一個登錄界面中仑濒,我的model層就是實現(xiàn)登錄密碼檢驗的功能偷遗。
首先,我們需要有一個對象類矗烛,來表達我們需要檢驗的對象箩溃。

public class User {
    private String name;
    private String password;

    public User(String name,String password){
        this.name = name;
        this.password = password;
    }
    ...省略getter和setter
}

然后我們需要一個LoginModel的接口函數(shù),來申明我們的登錄所需要的函數(shù)歪架。

public interface LoginModel {
    void login(User user);
}

其次是model的實現(xiàn)類霹陡,實現(xiàn)我們剛才在LoginModel中申明的login函數(shù)。
這里我們延時2秒鐘攒霹,用于模擬登陸效果浆洗。

public class LoginModelImpl implements LoginModel{
    @Override
    public void login(User user) {
        final String name = user.getName();
        final String password = user.getPassword();

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Boolean error =false;
                if (TextUtils.isEmpty(name)){
                    error = true;
                    //輸入錯誤
                    System.out.println("輸入錯誤");
                }
                if (TextUtils.isEmpty(password)){
                    error = true;
                    //輸入錯誤
                    System.out.println("輸入錯誤");
                }
                if(!error){
                    //登錄成功
                    System.out.println("登錄成功");
                }
            }
        },2000);
    }
}

View層:

對應(yīng)的界面布局伏社,以及界面布局的方法。
這里我們需要實現(xiàn)的waitDialog的顯示與消失速妖,以及登錄成功和失敗的提醒聪黎,所以建立我們的view接口類,LoginView.

public interface LoginView {
    void loginSuccess();
    void ErrorPass();
    void ErrorEnter();

    void showDialog();
    void hideDialog();
}

然后我們的實例就是Activity锦秒,使Acitivity繼承我們的接口湘纵,實現(xiàn)我們接口中的方法。

    //申明persenter實例
    LoginPresenter presenter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        ButterKnife.bind(this);

        btn.setOnClickListener(this);
        //通過Presenter實例類申明presenter
        presenter = new LoginPresenterImpl(this);
    }
    

    @Override
    public void loginSuccess() {
        Toast.makeText(this,"登錄成功",Toast.LENGTH_SHORT).show();
    }

    @Override
    public void ErrorPass() {
        Toast.makeText(this,"密碼錯誤",Toast.LENGTH_SHORT).show();
    }

    @Override
    public void ErrorEnter() {
        Toast.makeText(this,"輸入錯誤",Toast.LENGTH_SHORT).show();
    }

    @Override
    public void showDialog() {
        loginProgress.setVisibility(View.VISIBLE);
    }

    @Override
    public void hideDialog() {
        loginProgress.setVisibility(View.GONE);
    }
    
    @Override
    public void onClick(View v) {
        User user = new User(name.getText().toString(), password.getText().toString());
        //將檢驗事件回調(diào)給presenter砌左,讓他通知model進行檢驗
        presenter.checkLogin(user);
    }
}

Presenter層:

接下來是重點了汇歹,我們的Presenter類偿凭。
傳遞
作為view和model的中間傳達者。view告訴presenter需要檢驗了痰哨,然后presenter在告訴model,并把得到的user值給model斤斧,讓model進行檢驗。
申明presenter的接口類蕊连。

public interface LoginPresenter {
    void checkLogin(User user);
}

接口實現(xiàn)類LoginPresenterImpl,我們在presenter的實例中游昼,獲取到view和model的實例,然后在里面對其進行信息傳遞载庭。

public class LoginPresenterImpl implements LoginPresenter,LoginModelListener{
    LoginView view;
    LoginModel model;

    public LoginPresenterImpl(LoginView loginView){
        //從Activity中獲取到對view的引用
        this.view = loginView;
        //申明一個新的model
        model = new LoginModelImpl();
    }

    @Override
    public void checkLogin(User user) {
        //保證視圖是存在的
        if (view == null){
            return;
        }
        //顯示view中的dialog昧捷,然后對user信息進行驗證
        view.showDialog();
        model.login(user,this);
    }
}

這樣我們就實現(xiàn)了將view的事件罐寨,通過presenter傳遞給了model層,讓他去處理這一次的檢驗事件跋破,但是大家有沒有發(fā)現(xiàn)瓶蝴,我們是將這個事件傳遞給了model,但是model在處理完了之后舷手,他又怎么將得到的結(jié)果通知給presenter呢男窟?因為我們要避免view和model直接接觸。所以在這里歉眷,我們還需要一個listenter的接口類汗捡,讓presenter繼承這個接口,在傳遞給model的時候,攜帶接口一起傳過去盗胀。然后model通過這個接口告訴presenter淡溯,presenter再去通知view。

public interface LoginModelListener {
    void loginSuccess();
    void loginError();
}
public interface LoginModel {
    void login(User user, LoginModelListener listener);
}
public class LoginModelImpl implements LoginModel{
    @Override
    public void login(User user, final LoginModelListener listener) {
        final String name = user.getName();
        final String password = user.getPassword();

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Boolean error =false;
                if (TextUtils.isEmpty(name)){
                    error = true;
                    //輸入錯誤
                    System.out.println("輸入錯誤");
                    listener.loginError();
                }
                if (TextUtils.isEmpty(password)){
                    error = true;
                    //輸入錯誤
                    System.out.println("輸入錯誤");
                    listener.loginError();
                }
                if(!error){
                    //登錄成功
                    System.out.println("登錄成功");
                    listener.loginSuccess();
                }
            }
        },2000);
    }
}

至此强品,我們就實現(xiàn)了一個簡單的MVP的demo,是不是覺得Acitivity里面的邏輯很簡單了琼了,看著一下字就輕松了很多夫晌。

三、總結(jié)

那么我們現(xiàn)在結(jié)合剛才的案例所袁。我們再來總結(jié)一下凶掰。

因為我們要保證view和model直接不能直接通信,所有之間的交互懦窘,我們都要通過presenter這一個中間類來進行傳遞畅涂。persenter中擁有view和model的引用,然后午衰,view中有事件產(chǎn)生時苇经,將事件以及需要的參數(shù)傳給presenter,presenter再交給model扇单,待model處理完了之后,將反饋信息傳給presenter施流,presenter再將返回結(jié)果告訴view,最后呈現(xiàn)給用戶忿晕。

流程圖

github代碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末践盼,一起剝皮案震驚了整個濱河市宾巍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌肄程,老刑警劉巖选浑,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件古徒,死亡現(xiàn)場離奇詭異,居然都是意外死亡崎苗,警方通過查閱死者的電腦和手機舀寓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來必尼,“玉大人篡撵,你說我怎么就攤上這事∪眩” “怎么了膛檀?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長泳炉。 經(jīng)常有香客問我,道長氧腰,這世上最難降的妖魔是什么刨肃? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任之景,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘焕参。我一直安慰自己,他們只是感情好刻帚,可當(dāng)我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布崇众。 她就那樣靜靜地躺著航厚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪眯漩。 梳的紋絲不亂的頭發(fā)上麻顶,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天,我揣著相機與錄音队萤,去河邊找鬼矫钓。 笑死舍杜,一個胖子當(dāng)著我的面吹牛盈电,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播熬词,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼互拾,長吁一口氣:“原來是場噩夢啊……” “哼嚎幸!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起嫉晶,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡冷守,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年拍摇,在試婚紗的時候發(fā)現(xiàn)自己被綠了译断。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡堪唐,死狀恐怖翎蹈,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情合陵,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布踏拜,位于F島的核電站低剔,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏姻锁。R本人自食惡果不足惜猜欺,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望涧黄。 院中可真熱鬧赋荆,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至油挥,卻和暖如春款熬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背贤牛。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工殉簸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留沽讹,地道東北人武鲁。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓沐鼠,卻偏偏與公主長得像,于是被迫代替她去往敵國和親刽沾。 傳聞我的和親對象是個殘疾皇子排拷,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容