Android MVP框架學(xué)習(xí)實(shí)踐
前言
想著互聯(lián)網(wǎng)公司都基本都有現(xiàn)成的項(xiàng)目,實(shí)習(xí)的話最多也就是對(duì)原有的代碼修改,增加功能。所以***進(jìn)了一家不大不小的外包公司,想體驗(yàn)一下一個(gè)商業(yè)項(xiàng)目從落地到成型的過(guò)程。進(jìn)入公司以后,被分配到一個(gè)給國(guó)外發(fā)包方做的項(xiàng)目(我只是個(gè)實(shí)習(xí)生萌新啊,***個(gè)項(xiàng)目就給外國(guó)人做,這樣好嗎喂)。
作為一個(gè)有過(guò)Android開(kāi)發(fā)經(jīng)驗(yàn)的菜鳥(niǎo),也算在各個(gè)服務(wù)外包比賽中拿過(guò)些獎(jiǎng)的人(雖然大學(xué)的這種比賽很水,但是也是有些開(kāi)發(fā)的工作量的,哈哈),我對(duì)一個(gè)項(xiàng)目的構(gòu)成,如何開(kāi)發(fā)等等,都有些了解。由于之前的比賽項(xiàng)目經(jīng)驗(yàn),都是我一個(gè)人獨(dú)立開(kāi)發(fā)Android端,所以對(duì)項(xiàng)目的架構(gòu)、框架等都是怎么方便怎么來(lái),不怎么考慮代碼的可讀性,可復(fù)用性之類的東西(進(jìn)入公司實(shí)習(xí)之后才發(fā)現(xiàn),這些東西相當(dāng)重要啊),之前為了方便,把業(yè)務(wù)邏輯,視圖綁定啥的都一股腦的放入activity類中,導(dǎo)致activity類過(guò)于臃腫,給代碼的閱讀和修改都帶了極大的不便,但是由于自己的項(xiàng)目經(jīng)驗(yàn)缺乏,從一開(kāi)始就給自己挖下的坑,之后不但很難填,而且還越挖越深(單手捂眼笑哭.jpg),幸好只是我一個(gè)人自己開(kāi)發(fā),不然要是協(xié)作開(kāi)發(fā)的話,估計(jì)會(huì)被小伙伴怒錘。
進(jìn)入公司以后,從Android帶隊(duì)開(kāi)發(fā)大佬那邊拿到了項(xiàng)目的基礎(chǔ)開(kāi)發(fā)框架
品了一下,從我裸考過(guò)六級(jí)的水平來(lái)看,嗯,這個(gè)presenter應(yīng)該是之前在書上看到過(guò)的MVP中的P沒(méi)差了。從網(wǎng)上找找資料學(xué)習(xí)學(xué)習(xí)。
進(jìn)入正題。
MVP是Model、View、Presenter的縮寫。Model表示模型,主要負(fù)責(zé)數(shù)據(jù)的加載;VIew表示視圖主要負(fù)責(zé)視圖綁定,界面的展示,界面邏輯跳轉(zhuǎn)等;Presenter是表示器,主要作為View和Model的中間人,完成他們之間的交互,從而實(shí)現(xiàn)高內(nèi)聚低耦合的思想。畫了一幅它們之間的關(guān)系圖。
可能這樣有點(diǎn)抽象,talk is cheap, show you the code.
先來(lái)看看我們項(xiàng)目組Android大佬的MVP框架實(shí)現(xiàn),
MainActivity.java:
MainContract.java:
MainPresenter.java:
大佬果然是大佬,已經(jīng)對(duì)各種基類進(jìn)行了封裝,來(lái)方便我們這些萌新的開(kāi)發(fā)。(上面的代碼還用到了RxJava,emmmm其實(shí)這個(gè)對(duì)于我這個(gè)萌新來(lái)說(shuō)也是還沒(méi)有接觸過(guò)的技術(shù),之后也會(huì)更新RxJava相關(guān)的學(xué)習(xí)博客,要努力變強(qiáng)~)。
我們會(huì)發(fā)現(xiàn),其實(shí)上面這三個(gè).java已經(jīng)可以實(shí)現(xiàn)一個(gè)界面的完整邏輯,但是View有了,Presenter也有了,Model去哪了???還有Contract又是什么鬼???這還是MVP的設(shè)計(jì)模式嗎???
一開(kāi)始,我也是懵的,又去大佬那邊學(xué)習(xí)了一波。了解到,目前Android的MVP設(shè)計(jì)模式其實(shí)還沒(méi)有一個(gè)統(tǒng)一的標(biāo)準(zhǔn),基于MVP這個(gè)思想可以有很多的實(shí)現(xiàn)方式,上面展示的這個(gè)方式是Google官方提出的一種MVP實(shí)現(xiàn)方式。
谷歌官方的MVP實(shí)現(xiàn)方式中,弱化了Model的作用,將Model融入到了Presenter中,我們可以看到MainPresenter中的getBook方法,其實(shí)就是Model的實(shí)現(xiàn)。而Contract類,中文翻譯就是契約類,契約這個(gè)詞很形象,它作為view和presenter之間的接口,定義了view和presenter上所要實(shí)現(xiàn)的方法,然后view和presenter再各自實(shí)現(xiàn)其方法,讓整個(gè)界面的邏輯變得相當(dāng)清晰。
由于大佬的代碼經(jīng)過(guò)了封裝,有些細(xì)節(jié)被隱藏了,所以我們來(lái)做個(gè)小demo,用谷歌官方的MVP實(shí)現(xiàn)方式來(lái)實(shí)現(xiàn)一個(gè) --模擬從服務(wù)器拉取信息展示到界面-- 的程序,更直觀的了解MVP。
我的表演
先看一下***呈獻(xiàn)的界面吧
界面布局很簡(jiǎn)單,就一個(gè)TextView和一個(gè)Button,布局文件xml就不貼出來(lái)了。主要的功能是點(diǎn)一下獲取數(shù)據(jù)的按鈕,模擬從服務(wù)器獲取數(shù)據(jù),然后在textview上顯示出來(lái)。
下面的代碼結(jié)構(gòu),由Activity(也就是View)、Presenter、Contract組成:
為了講解方便,我們先來(lái)看一下MainContract里的內(nèi)容:
相當(dāng)簡(jiǎn)單,因?yàn)镃ontract是一個(gè)契約類,里面并沒(méi)有實(shí)現(xiàn)任何功能,只是寫明了Presenter和View分別要實(shí)現(xiàn)的接口,我在Presenter接口中定義了LoadData的方法,MainPresenter需要實(shí)現(xiàn)Presenter接口中的LoadData方法,來(lái)完成對(duì)數(shù)據(jù)從服務(wù)器的拉取;在接口View中定義了onDataLoaded的方法,同樣,因?yàn)镸ainActivity應(yīng)用了接口View,因此需要對(duì)onDataLoaded方法進(jìn)行實(shí)現(xiàn)。
MainActivity:
MainActivity主要是界面組件的綁定,以及一些成員變量的初始化,可以看到我這里初始化了textview、button還有一個(gè)presenter,之后界面關(guān)于數(shù)據(jù)的操作就通過(guò)presenter來(lái)實(shí)現(xiàn)。
我們可以看到,這里重寫了onDataLoaded的方法,因?yàn)镸ainActivity implements了契約類中的View接口,因此需要將接口中的onDataLoaded方法實(shí)現(xiàn),該方法的主要功能就是將presenter中獲取到的數(shù)據(jù)呈現(xiàn)在界面上,我們這邊是將數(shù)據(jù)顯示在界面的textview上。
MainPresenter:
MainPresenter是界面數(shù)據(jù)操作實(shí)現(xiàn)的地方,他implements了契約類的Presenter接口,因此需要實(shí)現(xiàn)Presenter接口中定義的LoadData方法,該方法的功能是從服務(wù)器獲取數(shù)據(jù)然后回調(diào)給Activity(也就是View),我這邊偷懶了,沒(méi)有服務(wù)器獲取數(shù)據(jù),直接hard code出數(shù)據(jù)(嘻嘻),嗯,假裝獲取到了服務(wù)器端的數(shù)據(jù),然后調(diào)用View的onDataLoaded方法,將所獲取到的數(shù)據(jù)傳遞到activity中。這樣activity中就可以更新數(shù)據(jù)了。
奧,對(duì)了,Presenter中必須有一個(gè)View的成員變量MainContract.View mView; 不然就不能調(diào)用view上面的方法了,mView的初始化,在Presenter變量創(chuàng)建的時(shí)候復(fù)制,可以在MainActivity中看到
看一下運(yùn)行的結(jié)果
由此,我們已經(jīng)實(shí)現(xiàn)了一個(gè)相當(dāng)相當(dāng)簡(jiǎn)單的基于MVP框架的app。
如果之后需要加功能,只要在Contract中添加所需要功能的接口,然后再在Presenter和Activity中分別實(shí)現(xiàn)就行。
比如說(shuō)我要新增一functionA,執(zhí)行完后需要在View上做出相應(yīng)的界面改變。我們只需要這樣做:
1、在Contract中定義Presenter中functionA方法,以及View中的onFunctionAFinished方法
2、在Presenter實(shí)現(xiàn)類中實(shí)現(xiàn)functionA具體方法,并調(diào)用更新界面的onFunctionAFinished
3、在Activity中實(shí)現(xiàn)onFunctionAFinished方法
這樣,又一個(gè)功能被添加了,是不是很方便,邏輯也很清晰。Activity只需負(fù)責(zé)界面更新的部分,而數(shù)據(jù)的獲取,全都交由Presenter來(lái)實(shí)現(xiàn),高內(nèi)聚低耦合,對(duì)于界面的維護(hù)和開(kāi)發(fā)相當(dāng)有幫助。
當(dāng)然,以上只是MVP一個(gè)最簡(jiǎn)單不過(guò)的實(shí)現(xiàn)了,為了易于理解,我對(duì)很多基類的定義和封裝都去掉了,在實(shí)際的開(kāi)發(fā)中是不可能那么簡(jiǎn)單的,但是,如果對(duì)于MVP的思想理解了,實(shí)現(xiàn)起來(lái)還是思路很清晰的。
再貼上上面代碼的github地址吧,雖然沒(méi)幾行代碼,但是不貼顯得不專業(yè),公司的開(kāi)發(fā)框架代碼我是不會(huì)貼的,貼的是我的簡(jiǎn)單代碼。
https://github.com/reggie1996/mvp_demo