Android Mvp 如今被普遍的應用在Android開發項目中,如今個人項目也使用了這種開發設計模式。java
當咱們的項目越龐大,複雜,參與的人員愈來愈多的時候,mcp的優勢就展示出來了。設計模式
Mvc與Mvp的區別:服務器
Mvc模式:網絡
Activity應該是屬於View這一層。而實質上,它既承擔了View,同時也包含一些Controller的東西在裏面。這對於開發與維護來講不太友好,耦合度大高了。架構
MVC模式的結構分爲三部分,實體層的Model,視圖層的View,以及控制層的Controller。mvc
其中View層其實就是程序的UI界面,用於向用戶展現數據以及接收用戶的輸入異步
而Model層就是JavaBean實體類,用於保存實例數據ide
Controller控制器用於更新UI界面和數據實例佈局
Mvp模式:單元測試
把Activity的View和Controller抽離出來就變成了View和Presenter,這就是MVP模式。mvp屬於mvc的一個增強版設計模式。
在Android開發中Activity和fragment都屬於view層,負責展示給用戶的UI控件,以及接收用戶的輸入,此外還要負責展示的生命週期的工做。若是在它們代碼層在加上業務邏輯判斷,就會使的代碼看起來臃腫,不利於維護。並且多人進行開發同一個項目時,對於同一界面的增改增多,就會出現衝突,不利於多人開發。因此咱們採用mvp模式代替mvc,mvp中view展示層,只負責交互,展示,不負責邏輯判斷。Presenter負責全部的邏輯實現,Model負責獲取數據用的。
MVP的好處:
1.分離了視圖邏輯和業務邏輯,下降耦合度。
2.Activity只負責生命週期和與用戶交互的工做,代碼比較簡潔。
3.視圖邏輯和業務邏輯分別抽象到View和Presenter的接口中去,提升代碼的可閱讀性。
4.Presenter抽象成接口,能夠實現多個實現類,很方便的進行單元測試。
其中最重要的有三點:
相信不少人閱讀代碼的時候,都是從Activity開始的,對着一個1000+行代碼的Activity,看了都以爲難受。
使用MVP以後,Activity就能瘦身許多了,基本上只有FindView、SetListener以及Init的代碼。其餘的就是對Presenter的調用,還有對View接口的實現。這種情形下閱讀代碼就容易多了,並且你只要看Presenter的接口,就能明白這個模塊都有哪些業務,很快就能定位到具體代碼。Activity變得容易看懂,容易維護,之後要調整業務、刪減功能也就變得簡單許多。
通常單元測試都是用來測試某些新加的業務邏輯有沒有問題,若是採用傳統的代碼風格(習慣性上叫作MV模式,少了P),咱們可能要先在Activity裏寫一段測試代碼,測試完了再把測試代碼刪掉換成正式代碼,這時若是發現業務有問題又得換回測試代碼,咦,測試代碼已經刪掉了!好吧從新寫吧……
MVP中,因爲業務邏輯都在Presenter裏,咱們徹底能夠寫一個PresenterTest的實現類繼承Presenter的接口,如今只要在Activity裏把Presenter的建立換成PresenterTest,就能進行單元測試了,測試完再換回來便可。萬一發現還得進行測試,那就再換成PresenterTest吧。
Android APP 發生OOM的最大緣由就是出現內存泄露形成APP的內存不夠用,而形成內存泄露的兩大緣由之一就是Activity泄露(Activity Leak)(另外一個緣由是Bitmap泄露(Bitmap Leak))。
Java一個強大的功能就是其虛擬機的內存回收機制,這個功能使得Java用戶在設計代碼的時候,不用像C++用戶那樣考慮對象的回收問題。然而,Java用戶老是喜歡隨便寫一大堆對象,而後幻想着虛擬機能幫他們處理好內存的回收工做。但是虛擬機在回收內存的時候,只會回收那些沒有被引用的對象,被引用着的對象由於還可能會被調用,因此不能回收。
Activity是有生命週期的,用戶隨時可能切換Activity,當APP的內存不夠用的時候,系統會回收處於後臺的Activity的資源以免OOM。
採用傳統的MV模式,一大堆異步任務和對UI的操做都放在Activity裏面,好比你可能從網絡下載一張圖片,在下載成功的回調裏把圖片加載到 Activity 的 ImageView 裏面,因此異步任務保留着對Activity的引用。這樣一來,即便Activity已經被切換到後臺(onDestroy已經執行),這些異步任務仍然保留着對Activity實例的引用,因此係統就沒法回收這個Activity實例了,結果就是Activity Leak。Android的組件中,Activity對象每每是在堆(Java Heap)裏佔最多內存的,因此係統會優先回收Activity對象,若是有Activity Leak,APP很容易由於內存不夠而OOM。
採用MVP模式,只要在當前的Activity的onDestroy裏,分離異步任務對Activity的引用,就能避免 Activity Leak。
說了這麼多,沒看懂?好吧,我本身都沒看懂本身寫的,咱們仍是直接看代碼吧。
上面一張簡單的MVP模式的UML圖,從圖中能夠看出,使用MVP,至少須要經歷如下步驟:
建立IPresenter接口,把全部業務邏輯的接口都放在這裏,並建立它的實現PresenterCompl(在這裏能夠方便地查看業務功能,因爲接口能夠有多種實現因此也方便寫單元測試)
建立IView接口,把全部視圖邏輯的接口都放在這裏,其實現類是當前的Activity/Fragment
由UML圖能夠看出,Activity裏包含了一個IPresenter,而PresenterCompl裏又包含了一個IView而且依賴了Model。Activity裏只保留對IPresenter的調用,其它工做所有留到PresenterCompl中實現
Model並非必須有的,可是必定會有View和Presenter
經過上面的介紹,MVP的主要特色就是把Activity裏的許多邏輯都抽離到View和Presenter接口中去,並由具體的實現類來完成。這種寫法多了許多IView和IPresenter的接口,在某種程度上加大了開發的工做量,剛開始使用MVP的小夥伴可能會以爲這種寫法比較彆扭,並且難以記住。其實一開始想太多也沒有什麼卵用,只要在具體項目中多寫幾回,就能熟悉MVP模式的寫法,理解TA的意圖,以及享♂受其帶來的好處。
Talk is cheap, let me show you the code!
1.咱們初始化初始化接口BaseView,方法爲向activity顯示的回調方法。
2.初始化接口Presenter類,用戶處理業務邏輯的抽象類。
3.初始化接口Contract類,用來鏈接接口View和接口Presenter的鏈接類
4.Presenter處理業務邏輯的類的具體實現
/** * 做爲view與Model交互的中間紐帶,處理與用戶交互負責的邏輯 */ public class RecommendPresenter implements RecommendContract.Presenter{ private RecommendModel mModel;// 訪問網絡的Model private RecommendContract.View mView;// 負責activity的回調。 public RecommendPresenter(RecommendContract.View view) { this.mView = view; this.mModel = new RecommendModel(); } @Override public void requestDatas() { mView.showLodading();// 通知彈出加載對話框回調 // 訪問網絡獲取 推送 數據的接口。 mModel.getApps(new Callback<PageBean<AppInfo>>() { @Override public void onResponse(Call<PageBean<AppInfo>> call, Response<PageBean<AppInfo>> response) { if(response !=null){ // 返回數據回調 mView.showResult(response.body().getDatas()); } else{ // 訪問數據爲空的回調 mView.showNodata(); } // 關閉彈出的加載的對話框 mView.dimissLoading(); } @Override public void onFailure(Call<PageBean<AppInfo>> call, Throwable t) { // 關閉加載對話框回調 mView.dimissLoading(); // 彈出錯誤選擇框 mView.showError(t.getMessage()); } }); } }
5.Activity的具體實現
/** * 與用戶展現的activity或fragment的實現。 */ public class RecommendFragment extends Fragment implements RecommendContract.View { @BindView(R.id.recycle_view) RecyclerView mRecyclerView; private ProgressDialog mMProgressDialog; private RecommendPresenter mMPredenter; private RecomendAppAdatper mAdatper; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { View mView = inflater.inflate(R.layout.fragment_recomend, container, false); ButterKnife.bind(this, mView); mMProgressDialog = new ProgressDialog(getActivity());// 加載框 初始化 mMPredenter = new RecommendPresenter(this); isCreateView = true; return mView; } private void initRecycleView(List<AppInfo> datas) { //爲RecyclerView設置佈局管理器 mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); //爲RecyclerView設置分割線(這個能夠對DividerItemDecoration進行修改,自定義) mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.HORIZONTAL_LIST)); //動畫 mRecyclerView.setItemAnimator(new DefaultItemAnimator()); mAdatper = new RecomendAppAdatper(getActivity(), datas); mRecyclerView.setAdapter(mAdatper); } @Override public void showResult(List<AppInfo> datas) { initRecycleView(datas); } @Override public void showNodata() { Toast.makeText(getActivity(), "暫時無數據,請吃完飯再來", Toast.LENGTH_LONG).show(); } @Override public void showError(String msg) { Toast.makeText(getActivity(), "服務器開小差了:" + msg, Toast.LENGTH_LONG).show(); } @Override public void showLodading() { mMProgressDialog.show(); } @Override public void dimissLoading() { if (mMProgressDialog.isShowing()) { mMProgressDialog.dismiss(); } } }
這樣就架構出來了MVP模式代碼。