Android MVP模式面向接口寫法
首先我們需要知道m(xù)vp所代表的含義,m即model可以理解成用來獲取數(shù)據(jù)和處理數(shù)據(jù),v即view可以看成activity和fragment用來顯示數(shù)據(jù)和處理交互,p即presenter可以理解成用來提供數(shù)據(jù)。
三者關(guān)系:m層用來獲取數(shù)據(jù)然后將數(shù)據(jù)提供給p層,p層拿到數(shù)據(jù)后通過v層展示,其中m層和v層是不能直接進行交互的,通過p層這個橋梁進行交互。這其中p層會持有v層和m層的引用。(先讀懂)
理解上面的說法下面我們直接上手代碼:
為了減少接口文件我們可以把接口都聲明在Contract內(nèi)
public interface ContentContract { interface Model { } interface View { } interface Presenter { } } //這樣我們不需要寫三個接口文件
然后分別實現(xiàn)三個接口與之對應(yīng)的m層,v層,p層
//model public class ContentModel implements ContentContract.Model { } //view public class MainActivty extends BaseQuickActivty implements ContentContract.View { } //presenter public class ContentPresenter implements ContentContract.Presenter { }
首先我們需要考慮的是在v層我們需要做一些什么處理,然后在定義我們的方法。假如我們需要獲取首頁的banner數(shù)據(jù),這時候就可以在view中聲明一個方法用來接收banner數(shù)據(jù)。
public interface ContentContract { interface Model { } interface View { void getBanner(String str); } interface Presenter { } } //這時候activity實現(xiàn)此方法 public class MainActivty extends BaseQuickActivty implements ContentContract.View { @Override public void getBanner(String str) { } }
當v層已經(jīng)有了接收數(shù)據(jù)的方法時,那么數(shù)據(jù)從何而來了?我們在之前說過m層是用來獲取數(shù)據(jù)的 所以我們可以在m層中定義一個請求網(wǎng)絡(luò)的方法。
// public class ContentModel implements ContentContract.Model { //獲取banner public void sendHttpBannerData(OnListener<String> on){ //這里需要考慮一個問題,就是每次獲取請求后的數(shù)據(jù),我們需要傳遞給p層,所以需要一個回調(diào)處理 //我們可以對m層進一步封裝下 //代碼示例 okgo.post().ex(new CallBack(){ public void onSucces(String str){ on.onSuccess(str); } public void onFail(){ on.onFail(); } }); } } //封裝后的modle層 ,先提取一個基類BaseModel public interface BaseModel<T> { interface OnListener<T> { void onSuccess(T t); void onFail(int code, String msg); } } //modle實現(xiàn) interface Model<T> extends BaseModle<T> { }
現(xiàn)在數(shù)據(jù)獲取的方式已經(jīng)有了,那怎么傳遞給p層呢?我們在之前也說過p層會持有m層的引用,所以我們可以在p層中調(diào)用層方法。
public class ContentPresenter implements ContentContract.Presenter { private ContentModel mModel; private ContentContract.View mView; //當初始化的時候 同時持有v層和m層引用 public ContentPresenter(ContentContract.View m) { mView=m; mModel = new ContentModel(); } //定義一個send方法,在該方法中調(diào)用m層的請求數(shù)據(jù)方法 public void send(){ mModel.sendHttpBannerData(new BaseModel.OnListener<String>() { @Override public void onSuccess(String s) { //這里就可以直接使用v層方法處理數(shù)據(jù),在v層中我們已經(jīng)實想該函數(shù) mView.getBanner(s); } @Override public void onFail(int code, String msg) { } }); } }
最后一步就是初始化p
public class MainActivty extends BaseQuickActivty implements ContentContract.View { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //初始化p ContentPresenter contentPresenter = new ContentPresenter(this); contentPresenter.send();//調(diào)用p層的send方法 開始請求數(shù)據(jù) } @Override public void getBanner(String str) { } }
這樣我們就可以交互了,在接口中我們可以根據(jù)自己的需求增加方法,可以提供基類,這樣沒必要每次都重寫方法,可以將一些通用的放在基類中。(可以先消化下,接下來我們做進一步的處理和避免內(nèi)存泄漏問題)
我們分析下不足之處。
每一個presenter都需要每次重寫相同代碼,手動釋放p等不足之處。所以我們先從presenter入手.
/** * 基類 presenter 綁定view * * @param <T> */ public abstract class BasePresenter<T> { //弱引用 private WeakReference<T> mWeakReference; private ReferenceQueue<T> mReferenceQueue = new ReferenceQueue<>(); /** * 添加view進入隊列 * * @param t */ public void attachView(T t) { mWeakReference = new WeakReference<T>(t); } public T getView() { return mWeakReference.get(); } /** * 判斷是否綁定過view * * @return true 綁定 */ public boolean isViewAttachecd() { return mWeakReference != null && mWeakReference.get() != null; } /** * 清除view,這樣不用每次手動釋放 */ public void deleteAttach() { if (mWeakReference != null) { mWeakReference.clear(); mWeakReference = null; } } }
接著我們改進activity或者fragment的基類base
** * activity 基類 * v 代表 view * t presenter */ public abstract class BaseQuickActivity<V, T extends BasePresenter<V>> extends AppCompatActivity { protected T mPresenter; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mPresenter = createPresenter(); //這里做一下非空判斷 有可能某些模塊不需要mvp模式 if (mPresenter != null) { mPresenter.attachView((V) this); } } protected abstract T createPresenter(); @Override protected void onDestroy() { super.onDestroy(); if (mPresenter != null) { mPresenter.deleteAttach(); } } } //fragment 一樣的寫法
這樣我們基本上完善了mvp模式。mvp給我?guī)淼暮锰幒芏?,高度解耦,代碼結(jié)構(gòu)清晰(以前ac或者ft可以達到上千行代碼,現(xiàn)在都交給了p和m),便于測試(不會)。但是同時也有缺點,第一感知就是類增多了。第二感知就是在交互時有些時候不方便。
上述結(jié)構(gòu)體還是可以更加完善的,可以用eventbus或者rxjava用于溝通的橋梁和數(shù)據(jù)分發(fā)。
到此這篇關(guān)于Android MVP模式的寫法淺析的文章就介紹到這了,更多相關(guān)Android MVP模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android編程實現(xiàn)修改標題欄位置使其居中的方法
這篇文章主要介紹了Android編程實現(xiàn)修改標題欄位置使其居中的方法,涉及Android布局設(shè)置的簡單實現(xiàn)技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-11-11Android應(yīng)用中使用Fragment組件的一些問題及解決方案總結(jié)
這里我們講的Fragment主要探討的是support庫中的Fragment,包括Fragment常遇到的crash崩潰問題,嵌套Fragment收不到onActivityResult()回調(diào)以及一些常用tips等,需要的朋友可以參考下2016-05-05Android實現(xiàn)過渡動畫、引導頁 Android判斷是否第一次啟動App
這篇文章主要為大家詳細介紹了Android實現(xiàn)過渡動畫、引導頁,以及Android判斷是否第一次啟動App,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-12-12總結(jié)Android中多線程更新應(yīng)用的頁面信息的方式
這篇文章主要介紹了總結(jié)Android中多線程更新應(yīng)用的頁面信息的方式,文中共總結(jié)了runOnUiThread、Handler、AsyncTask異步以及View直接在UI線程中更新的方法,需要的朋友可以參考下2016-02-02Android?Studio中如何修改APP圖標和APP名稱
這篇文章主要介紹了Android?Studio中如何修改APP圖標和APP名稱,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-11-11Android開發(fā)實現(xiàn)可拖動排序的ListView功能【附源碼下載】
這篇文章主要介紹了Android開發(fā)實現(xiàn)可拖動排序的ListView功能,結(jié)合實例形式分析了Android列表拖動排序原理與相關(guān)操作技巧,并附帶完整源碼供讀者下載參考,需要的朋友可以參考下2017-11-11Android高級xml布局之輸入框EditText設(shè)計
這篇文章主要為大家詳細介紹了Android高級xml布局之輸入框EditText設(shè)計,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-12-12