Android-MVP設(shè)計(jì)模式(基礎(chǔ))

MVP 全稱:Model-View-Presenter

MVP 是從經(jīng)典的模式MVC演變而來(lái)瑞佩,它們的基本思想有相通的地方:Controller/Presenter負(fù)責(zé)邏輯的處理,Model提供數(shù)據(jù),View負(fù)責(zé)顯示。


模式描述

Model-view-presenter (MVP)使用者界面 設(shè)計(jì)模式的一種一疯,被廣范用于便捷自動(dòng)化單元測(cè)試和在呈現(xiàn)邏輯中改良分離關(guān)注點(diǎn)(separation of concerns)肘交。

  • Model 定義使用者界面所需要被顯示的資料模型,一個(gè)模型包含著相關(guān)的業(yè)務(wù)邏輯饲常。
  • View 視圖為呈現(xiàn)使用者界面的終端,用以表現(xiàn)來(lái)自 Model 的資料狼讨,和使用者命令路由再經(jīng)過(guò) Presenter 對(duì)事件處理后的資料贝淤。
  • Presenter 包含著元件的事件處理,負(fù)責(zé)檢索 Model 取得資料政供,和將取得的資料經(jīng)過(guò)格式轉(zhuǎn)換與 View 進(jìn)行溝通播聪。

下面一個(gè)圖就能很好展示它們之間的關(guān)系

Paste_Image.png

那我們開(kāi)始實(shí)例講解

現(xiàn)在我們做一個(gè)小Demo朽基。輸入一個(gè)qq號(hào),能查到QQ號(hào)碼吉兇
請(qǐng)求示例:
http://api.jisuapi.com/qqluck/query?qq=22222&appkey=yourappkey

Json返回示例

{
"status": "0",
"msg": "ok",
"result": {
    "qq": "22222",
    "score": "62",
    "luck": "兇",
    "content": "煩悶懊惱离陶,事事難展稼虎,自防災(zāi)禍,始免困境",
    "character": "要面包不要愛(ài)情",
    "characterdetail": "責(zé)任心重招刨,尤其對(duì)工作充滿熱誠(chéng)霎俩,是個(gè)徹頭徹尾工作狂。但往往因?yàn)檫^(guò)分專注職務(wù)沉眶,而忽略身邊的家人及朋友打却,是個(gè)寧要面包不需要愛(ài)情的理性主義者。"
}
}
Paste_Image.png

項(xiàng)目結(jié)構(gòu)

Paste_Image.png

其中api 是接口谎倔。bean 是javabean 用來(lái)作數(shù)據(jù)模型学密。model來(lái)進(jìn)行網(wǎng)絡(luò)請(qǐng)求獲取數(shù)據(jù)。presenter來(lái)進(jìn)行事件處理传藏。把處理好的數(shù)據(jù)通過(guò)一定方式傳給view 腻暮,也就是我們的activity,然后展示給用戶看毯侦。
所以這就結(jié)構(gòu)就看著非常簡(jiǎn)單哭靖。model 只做網(wǎng)絡(luò)請(qǐng)求,presenter把請(qǐng)求的數(shù)據(jù)處理好 傳給view侈离,然后view在展示給用戶看试幽。這中間view和model是沒(méi)有任何的關(guān)聯(lián),只是有個(gè)中間著presenter來(lái)進(jìn)行相應(yīng)的處理

我們接下來(lái)先把a(bǔ)pi 和bean 填上卦碾,代碼如下

網(wǎng)絡(luò)請(qǐng)求用的retrofit框架

compile 'com.squareup.retrofit2:retrofit:2.2.0'
compile 'com.squareup.retrofit2:converter-gson:2.2.0'
Paste_Image.png

MyService類铺坞,簡(jiǎn)單封裝網(wǎng)絡(luò)請(qǐng)求

public class MyService {

public static String baseUrl="http://api.jisuapi.com/qqluck/";
public static Retrofit mRetrofit=new Retrofit.Builder()
        .baseUrl(baseUrl)
        .addConverterFactory(GsonConverterFactory.create())
        .build();
public static <T> T getApi(Class<T> mClass){
    return mRetrofit.create(mClass);

}
}

DemoApi類, api接口類

public interface DemoApi {
@POST("query")
Call<QqluckData> loadqQuery(@Query("qq") int qq, @Query("appkey") String appkey);

}

接下來(lái)開(kāi)始寫view 洲胖。因?yàn)槲覀円鲆粋€(gè)qq兇吉济榨,那么就要把展示結(jié)果給用戶看。所以先寫一個(gè)接口.只有一個(gè)方法绿映。用來(lái)接收presenter傳過(guò)了的數(shù)據(jù)擒滑,展示給用戶看

public interface IMainView {
void showInfo(String response);
}

然后用Maintivivty來(lái)繼承IMainView接口,實(shí)現(xiàn)其中的方法叉弦,獲得數(shù)據(jù)丐一,展示給用戶看,代碼如下

public class MainActivity extends AppCompatActivity implements IMainView {
private TextView mluck;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mluck= (TextView) findViewById(R.id.luck);
}

public void onClick(View v){
    switch (v.getId()){
        case R.id.send:

            break;

    }

}

@Override
public void showInfo(String response) {
    mluck.setText(response);
}
}

現(xiàn)在基本完成了一半淹冰,下面接著寫model 的網(wǎng)絡(luò)請(qǐng)求
根據(jù)上面的請(qǐng)求示例库车,我們需要傳一個(gè)qq號(hào),和一個(gè)appkey樱拴。appkey去注冊(cè)申請(qǐng)一個(gè)就好柠衍,在這就不多說(shuō)潘拱,另外需要一個(gè)Callback回調(diào)函數(shù)。需要把請(qǐng)求到的數(shù)據(jù)傳給presenter拧略。model也到這差不多了。

public class MainModel {

public void getData( int qq, String appkey,  Callback<QqluckData> mCallback) {

    DemoApi api = MyService.getApi(DemoApi.class);
    Call<QqluckData> qqluckDataCall = api.loadqQuery(qq, appkey);
    qqluckDataCall.enqueue(mCallback);

}
}

現(xiàn)在就開(kāi)始寫presenter瘪弓,代碼如下

public class MainPresenter {
public IMainView mIMainView;//view 的引用
public MainModel mMainModel;//model的引用

public MainPresenter(IMainView IMainView) {
    mIMainView = IMainView;
    mMainModel=new MainModel();
}

public void load(int qq){//加載數(shù)據(jù)垫蛆。通過(guò)model 來(lái)獲取
    String appkey="34865d1e2ff7170f";
    mMainModel.getData(qq, appkey, new Callback<QqluckData>() {
        @Override
        public void onResponse(Call<QqluckData> call, Response<QqluckData> response) {
            //獲取到數(shù)據(jù)
            QqluckData body = response.body();
            //調(diào)用showInfo方法,傳遞數(shù)據(jù)腺怯。展示給用戶看
            mIMainView.showInfo("luck:"+body.getResult().getLuck()+"\ncontent:"+body.getResult().getContent());
        }

        @Override
        public void onFailure(Call<QqluckData> call, Throwable t) {

        }
    });

}
}

presenter 代碼沒(méi)多少袱饭。持有view 和midel的引用。 當(dāng)view初始化presenter時(shí)會(huì)把view 傳過(guò)來(lái)呛占。presenter內(nèi)部在持有Model的引用虑乖。當(dāng)用戶發(fā)起qq測(cè)吉兇功能時(shí),由view 調(diào)用presenter的load方法晾虑。presenter在由model去發(fā)送網(wǎng)絡(luò)請(qǐng)求疹味。把數(shù)據(jù)結(jié)果在傳回給view。下面我在把完整的Maintivit 貼出來(lái)

public class MainActivity extends AppCompatActivity implements IMainView {
private TextView mluck;
private MainPresenter mMainPresenter;
private EditText mEdqq;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mluck= (TextView) findViewById(R.id.luck);
    mEdqq= (EditText) findViewById(R.id.ed_qq);
    //onCreate時(shí)初始化MainPresenter帜篇,因?yàn)楫?dāng)前已繼承IMainView糙捺,直接傳this即可。這個(gè)時(shí)候MainPresenter就持有IMainView的引用了
    mMainPresenter=new MainPresenter(this);

}

public void onClick(View v){
    switch (v.getId()){
        case R.id.send:
            if(TextUtils.isEmpty(mEdqq.getText().toString())){
                return;
            }
//發(fā)送請(qǐng)求笙隙。調(diào)取MainPresenter.load的方法
      mMainPresenter.load(Integer.parseInt(mEdqq.getText().toString()));
            break;

    }

}

@Override
public void showInfo(String response) {
    //展示結(jié)果
    mluck.setText(response);

}
}

好了洪灯。到此一個(gè)簡(jiǎn)單的mvp demo已經(jīng)寫完了 。竟痰∏┕常或許有很多人在此覺(jué)得mvp 太麻煩了。一個(gè)簡(jiǎn)單的網(wǎng)絡(luò)請(qǐng)求坏快,寫的這么多類铅檩,這么多代碼。但是我要說(shuō)的是莽鸿,你看我們的activity類柠并。代碼是不是非常少,是不是很簡(jiǎn)潔富拗,其他的也都分工很明確臼予。耦合性也很低。便于后期維護(hù)啃沪,這個(gè)時(shí)候mvp 的優(yōu)點(diǎn)便體現(xiàn)出來(lái)了粘拾。
對(duì)了。展示一下結(jié)果

WechatIMG3.jpeg

MVP的優(yōu)點(diǎn)

  • 1创千、模型與視圖完全分離缰雇,我們可以修改視圖而不影響模型
  • 2入偷、可以更高效地使用模型,因?yàn)樗械慕换ザ及l(fā)生在一個(gè)地方——Presenter內(nèi)部
  • 3械哟、我們可以將一個(gè)Presenter用于多個(gè)視圖疏之,而不需要改變Presenter的邏輯。這個(gè)特性非常的有用暇咆,因?yàn)橐晥D的變化總是比模型的變化頻繁锋爪。
  • 4、如果我們把邏輯放在Presenter中爸业,那么我們就可以脫離用戶接口來(lái)測(cè)試這些邏輯(單元測(cè)試)

MVP的缺點(diǎn)

  • 由于對(duì)視圖的渲染放在了Presenter中其骄,所以視圖和Presenter的交互會(huì)過(guò)于頻繁。還有一點(diǎn)需要明白扯旷,如果Presenter過(guò)多地渲染了視圖拯爽,往往會(huì)使得它與特定的視圖的聯(lián)系過(guò)于緊密。一旦視圖需要變更钧忽,那么Presenter也需要變更了毯炮。比如說(shuō),原本用來(lái)呈現(xiàn)Html的Presenter現(xiàn)在也需要用于呈現(xiàn)Pdf了耸黑,那么視圖很有可能也需要變更否副。

如果有什么問(wèn)題不懂∑榉唬或者我那個(gè)地方寫的有問(wèn)題备禀。歡迎小伙伴提出。最后說(shuō)一下奈揍。MVP只是個(gè)設(shè)計(jì)模式曲尸。不一定非要按部就班。我們要活學(xué)活用男翰。適合自己的才是最好的另患。

源代碼
https://github.com/ccicec/AndroidMvpDemo/tree/master
A New Day

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蛾绎,隨后出現(xiàn)的幾起案子昆箕,更是在濱河造成了極大的恐慌,老刑警劉巖租冠,帶你破解...
    沈念sama閱讀 211,561評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鹏倘,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡顽爹,警方通過(guò)查閱死者的電腦和手機(jī)纤泵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)镜粤,“玉大人捏题,你說(shuō)我怎么就攤上這事玻褪。” “怎么了公荧?”我有些...
    開(kāi)封第一講書人閱讀 157,162評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵带射,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我循狰,道長(zhǎng)窟社,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 56,470評(píng)論 1 283
  • 正文 為了忘掉前任晤揣,我火速辦了婚禮,結(jié)果婚禮上朱灿,老公的妹妹穿的比我還像新娘昧识。我一直安慰自己,他們只是感情好盗扒,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,550評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布跪楞。 她就那樣靜靜地躺著,像睡著了一般侣灶。 火紅的嫁衣襯著肌膚如雪甸祭。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 49,806評(píng)論 1 290
  • 那天褥影,我揣著相機(jī)與錄音池户,去河邊找鬼。 笑死凡怎,一個(gè)胖子當(dāng)著我的面吹牛校焦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播统倒,決...
    沈念sama閱讀 38,951評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼寨典,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了房匆?” 一聲冷哼從身側(cè)響起耸成,我...
    開(kāi)封第一講書人閱讀 37,712評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎浴鸿,沒(méi)想到半個(gè)月后井氢,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,166評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡岳链,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,510評(píng)論 2 327
  • 正文 我和宋清朗相戀三年毙沾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宠页。...
    茶點(diǎn)故事閱讀 38,643評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡左胞,死狀恐怖寇仓,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情烤宙,我是刑警寧澤遍烦,帶...
    沈念sama閱讀 34,306評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站躺枕,受9級(jí)特大地震影響服猪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜拐云,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,930評(píng)論 3 313
  • 文/蒙蒙 一罢猪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧叉瘩,春花似錦膳帕、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,745評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至泳桦,卻和暖如春汤徽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背灸撰。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,983評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工谒府, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人浮毯。 一個(gè)月前我還...
    沈念sama閱讀 46,351評(píng)論 2 360
  • 正文 我出身青樓狱掂,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親亲轨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子趋惨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,509評(píng)論 2 348

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