仿Android官方MVP架構(gòu)實(shí)現(xiàn)

1.關(guān)于MVP架構(gòu)

有時(shí)候在實(shí)現(xiàn)一個(gè)APP的時(shí)候會(huì)發(fā)現(xiàn)亮蛔,寫著寫著Activity中的代碼會(huì)越來越多,控件和數(shù)據(jù)的初始化沒有問題浴讯。當(dāng)添加按鈕并綁定監(jiān)聽事件時(shí)候有網(wǎng)絡(luò)訪問朵夏,往往直接寫在OnClick()方法中(我以前就是這么干的),Activity中的代碼馬上就變得十分冗余榆纽,當(dāng)中出現(xiàn)了業(yè)務(wù)邏輯侍郭,數(shù)據(jù)訪問部分询吴,Activity簡直變成了一個(gè)萬能類。
Activity變成萬能類的后果是亮元,代碼變得龐大并且臃腫,代碼間嚴(yán)重耦合唠摹,改一個(gè)小部分往往牽一發(fā)而動(dòng)全身爆捞,而且代碼的可讀性很差,想象一下在一個(gè)功能眾多的Activity中尋找某一個(gè)功能某塊的場景勾拉。
這就誕生了各種APP分層架構(gòu)煮甥,其中MVP架構(gòu)是最近十分流行的APP架構(gòu)。


MVP的全稱為:Model-View-Presenter
MVP將APP劃分為三層藕赞,Model層負(fù)責(zé)數(shù)據(jù)存儲(chǔ)與數(shù)據(jù)處理成肘,View負(fù)責(zé)展示數(shù)據(jù),Presenter層負(fù)責(zé)具體的業(yè)務(wù)邏輯斧蜕。
雖然網(wǎng)上的對于MVP介紹的文章看了不少双霍,但是MVC都還沒搞明白,對于MVP就更是處于一知半解的狀態(tài)批销,剛好Google官方在Github上推出了一個(gè)項(xiàng)目實(shí)例(點(diǎn)擊查看)洒闸,用于展示Android各種各樣的MVP架構(gòu),其中的todo-mvp屬于MVP基礎(chǔ)架構(gòu)實(shí)例均芽,即使是基礎(chǔ)架構(gòu)的實(shí)現(xiàn)方案也使我受益匪淺丘逸,并仿照todo-mvp實(shí)現(xiàn)了一個(gè)小的案例。

2.案例介紹

在案例中使用了http://gank.io/api提供的福利接口掀宋,可從中獲取各種妹子的福利照片并展示深纲。
項(xiàng)目結(jié)構(gòu):

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

(1)BaseView和BasePresenter兩個(gè)基類接口。

BaseView.java:

public interface BaseView<T> {    
    void setPresenter(T presenter);
}

BasePresenter.java:

public interface BasePresenter {
    void start();
}

所有的View和Presenter首先實(shí)現(xiàn)這兩個(gè)基類接口劲妙。
其中BaseView的setPresenter(T presenter)方法用于綁定View對應(yīng)的Presenter湃鹊,BasePresenter的start()方法用于初始化時(shí)執(zhí)行相應(yīng)的邏輯。

(2)具體的實(shí)現(xiàn)接口

之后在特定的功能中是趴,在契約類WelfareDetailContact.java中聲明具體的View和Presenter接口涛舍,在其中聲明實(shí)現(xiàn)的具體功能。
WelfareDetailContact.java:

public interface WelfareDetailContact {
    interface View extends BaseView<Presenter> {
        void showPic(Welfare data);
    }
    interface Presenter extends BasePresenter {
        void displayHome();
        void refreshRandom();
    }
}

其中View的showPic(Welfare data)方法只負(fù)責(zé)根據(jù)結(jié)構(gòu)化的數(shù)據(jù)進(jìn)行相應(yīng)的顯示唆途,Presenter的兩個(gè)方法只負(fù)責(zé)展示主頁和隨機(jī)刷新邏輯(目前只添加了這兩個(gè)邏輯)富雅。
具體的WelfareDetailView與WelfareDetailPresenter需實(shí)現(xiàn)契約類中的兩個(gè)接口。

(3)Model數(shù)據(jù)層

WelfareDataSource.java:

public interface WelfareDataSource {
    interface GetCallback {
        void onWelfareGet(Welfare welfare);
        void onDataNotAvailable();
    }
    void queryHome(GetCallback callback);
    void queryPage(String page, GetCallback callback);
    void queryRandom(GetCallback callback);
}

此接口聲明了獲取數(shù)據(jù)的方法和回調(diào)接口肛搬。
實(shí)現(xiàn)此接口的一共有三個(gè)類:WelfareRepository没佑,WelfareLocalDataSource和WelfareRemoteDataSource。
WelfareRepository 負(fù)責(zé)總調(diào)度温赔,WelfareLocalDataSource負(fù)責(zé)本地?cái)?shù)據(jù)的加載與存儲(chǔ)蛤奢,WelfareRemoteDataSource負(fù)責(zé)網(wǎng)絡(luò)遠(yuǎn)程數(shù)據(jù)的獲取。
在本地和遠(yuǎn)程數(shù)據(jù)獲取時(shí),都會(huì)將JSON數(shù)據(jù)組裝成Welfare對象后傳入回調(diào)接口啤贩。
WelfareRepository 作為負(fù)責(zé)的總調(diào)度待秃,分別持有WelfareLocalDataSource和WelfareRemoteDataSource的實(shí)例引用。三個(gè)類均使用單例模式痹屹。
下面看看具體實(shí)現(xiàn):
總調(diào)度類WelfareRepository
WelfareRepository.java:

public class WelfareRepository implements WelfareDataSource {
    private WelfareLocalDataSource mLocalDataSource;
    private WelfareRemoteDataSource mRemoteDataSource;
    ......
    @Override
    public void queryHome(final GetCallback callback) {
        mLocalDataSource.queryHome(new GetCallback() {
            @Override
            public void onWelfareGet(Welfare welfare) {
                callback.onWelfareGet(welfare);
            }
            @Override
            public void onDataNotAvailable() {
                mRemoteDataSource.queryHome(new GetCallback() {
                    @Override
                    public void onWelfareGet(Welfare welfare) {
                        callback.onWelfareGet(welfare);
                        mLocalDataSource.updateWelfare(welfare);
                    }
                    @Override
                    public void onDataNotAvailable() {

                    }
                });
            }
        });
    }
    ......
}

以queryHome()查詢主頁為例章郁,總調(diào)度WelfareRepository先是調(diào)用了WelfareLocalDataSource實(shí)例的queryHome()方法進(jìn)行本地讀取,若是本地讀取成功志衍,則正常執(zhí)行傳入的回調(diào)暖庄;若是本地?cái)?shù)據(jù)獲取失敗,則調(diào)用WelfareRemoteDataSource實(shí)例的queryHome()方法獲取網(wǎng)絡(luò)數(shù)據(jù)請求楼肪,成功時(shí)正常執(zhí)行回調(diào)培廓,并在本地進(jìn)行存儲(chǔ)。

(4)具體View和Presenter的實(shí)現(xiàn)類春叫。

WelfareDetailFragment.java:

public class WelfareDetailFragment extends Fragment implements WelfareDetailContact.View {
    private WelfareDetailContact.Presenter mPresenter;
    ......
    @Override
    public void showPic(Welfare data) {
        mAdapter.setData(data.results);
        mAdapter.notifyDataSetChanged();
    }
    @Override
    public void setPresenter(WelfareDetailContact.Presenter presenter) {
        this.mPresenter = presenter;
    }
    @Override
    public void onResume() {
        super.onResume();
        mPresenter.start();
    }
}

在實(shí)例中使用Fragment來代替Activity來執(zhí)行View的角色肩钠,這使得Activity中的代碼更為簡潔,使角色分工更加明確象缀。
可以看到蔬将,WelfareDetailFragment作為View的角色,持有Presenter的引用央星,并在onResume()方法中調(diào)用mPresenter.start()來執(zhí)行初始化時(shí)需要執(zhí)行的邏輯霞怀。

WelfareDetailPresenter.java:

public class WelfareDetailPresenter implements WelfareDetailContact.Presenter {
    private WelfareRepository mWelfareRepository;
    private WelfareDetailContact.View mView;
    ......
    public WelfareDetailPresenter(WelfareRepository welfareRepository, WelfareDetailContact.View view) {
        this.mWelfareRepository = welfareRepository;
        this.mView = view;
        view.setPresenter(this);
    }
    @Override
    public void start() {
        displayHome();
    }
    @Override
    public void displayHome() {
        mWelfareRepository.queryHome(new WelfareDataSource.GetCallback() {
            @Override
            public void onWelfareGet(Welfare welfare) {
                mView.showPic(welfare);
            }
            @Override
            public void onDataNotAvailable() {

            }
        });
    }
}

WelfareDetailPresenter在構(gòu)造初始化時(shí)與相應(yīng)的View進(jìn)行綁定,并且分別持有WelfareRepository和View實(shí)例引用莉给。
以start()初始化中調(diào)用的displayHome()方法為例毙石,在具體的實(shí)現(xiàn)中,通過對兩個(gè)實(shí)例的操作來進(jìn)行相應(yīng)的業(yè)務(wù)邏輯颓遏。簡單來說徐矩,就是對Model層和View層實(shí)例提供的功能進(jìn)行組合,使邏輯更加清晰叁幢,沒有多余的代碼滤灯。

(5)項(xiàng)目示例

示例圖

通過仿照官方示例聲明一些列的接口,實(shí)現(xiàn)了Model層-View層-Presenter層的分離曼玩,使代碼和邏輯更加的清晰鳞骤,具體源碼托管在我的Github主頁(點(diǎn)擊查看)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末黍判,一起剝皮案震驚了整個(gè)濱河市豫尽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌顷帖,老刑警劉巖美旧,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件渤滞,死亡現(xiàn)場離奇詭異,居然都是意外死亡榴嗅,警方通過查閱死者的電腦和手機(jī)妄呕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來录肯,“玉大人趴腋,你說我怎么就攤上這事÷塾剑” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵颁井,是天一觀的道長厅贪。 經(jīng)常有香客問我,道長雅宾,這世上最難降的妖魔是什么养涮? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮眉抬,結(jié)果婚禮上贯吓,老公的妹妹穿的比我還像新娘。我一直安慰自己蜀变,他們只是感情好悄谐,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著库北,像睡著了一般爬舰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上寒瓦,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天情屹,我揣著相機(jī)與錄音,去河邊找鬼杂腰。 笑死垃你,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的喂很。 我是一名探鬼主播惜颇,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼恤筛!你這毒婦竟也來了官还?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤毒坛,失蹤者是張志新(化名)和其女友劉穎望伦,沒想到半個(gè)月后林说,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡屯伞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年腿箩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片劣摇。...
    茶點(diǎn)故事閱讀 38,716評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡珠移,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出末融,到底是詐尸還是另有隱情钧惧,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布勾习,位于F島的核電站浓瞪,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏巧婶。R本人自食惡果不足惜乾颁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望艺栈。 院中可真熱鬧英岭,春花似錦、人聲如沸湿右。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽诅需。三九已至漾唉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間堰塌,已是汗流浹背赵刑。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留场刑,地道東北人般此。 一個(gè)月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像牵现,于是被迫代替她去往敵國和親铐懊。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評論 2 350

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