Android - MVP

淺談 MVP in Android前端

 https://www.jianshu.com/p/4736ebe1114bgit

 

鴻洋大神寫的,MVP模式的基礎介紹github

 

傳統MVP的弊端:數據庫

MVP須要建立太多的類和接口,而且每次通訊都須要繁瑣的經過接口傳遞信息緩存

 

軟解決,那就要動動腦子,稍微優雅的解決了網絡

  1. 對於邏輯簡單的頁面能夠不使用Presenter,直接在ActivityFragment中處理邏輯,在Presenter中若是不須要處理數據,也能夠不使用Model架構

  2. PresenterModel均可以無限制的重用,因此MVP的劃分不須要太細粒度,稍微粗粒度一點,即不須要每一個ActivityFragment都給他劃分一套MVP,能夠幾個ActivityFragment使用同一個Presenter(使用同一個類不是同一個對象,這個Presenter含有能夠共用的邏輯),也可一個ActivityFragment根據不一樣的需求持有多個不一樣類型的Presenter對象,Model層同理,這樣靈活使用,能夠在必定程度上緩解MVP類和接口較多的缺點app

經過上面的解決方案,是能夠必定的緩解MVP的缺點,可是並不能徹底解決上述缺點框架

好比想重用Presenter,Presenter就必須只含有公用的邏輯,而實際項目中公用的邏輯並非那麼多,因此能減小的類和接口也是頗有限的,若是強制將不一樣頁面的邏輯放在同一個Prsenter中,來達到重用的目的,那麼每一個Activity會被迫實現許多並不須要的方法,得不償失異步

總結一下MVP的缺點:
1.粒度很差控制,控制很差就須要寫過多的類和接口 2.如要重用presenter可能會實現過多不須要的接口 3.Presenter和View經過接口通訊太繁瑣,一旦View層須要的數據變化,那麼對應的接口就須要更改

 

如何更高效的使用MVP以及官方MVP架構解析

 

presenter一直持有Activity對象致使的內存泄漏問題

寫mvp的時候,presenter會持有view,若是presenter有後臺異步的長時間的動做,好比網絡請求,這時若是返回退出了Activity,後臺異步的動做不會當即中止,這裏就會有內存泄漏的隱患,因此會在presenter中加入一個銷燬view的方法

 

BasePresenter

通用的presenter來爲咱們添加view的綁定與銷燬

//presenter中添加mvpView 置爲null的方法
public void onDestroy(){    
    mvpView = null;
}

//退出時銷燬持有Activity
@Override
protected void onDestroy() {    
    mvpPresenter.onDestroy();    
    super.onDestroy();
}

 

BaseView

界面須要提供的UI方法中會有不少相似的UI方法,能夠把它們提取到一個公共的父類接口中。好比提取顯示loading界面和隱藏loading界面的方法,其餘的view層接口就能夠直接繼承BaseView接口,沒必要重複的寫顯示和隱藏loading界面方法。

 

BaseMvpActivity

presenter綁定到activity和View的綁定和解綁操做是每一個Activity都會去作的,一樣這裏我也但願能有一個父類來完成這個統一的操做。

 

Dagger的用處

構建一個對象有時候還要構建一堆其餘的對象,而且其餘對象的構建一樣複雜,而且必須按順序構建,並且須要的對象的生命週期都不同,有些生命週期可能和Activity同樣,有些多是單例,因此在構建的時候還要考慮對象聲明週期,考慮對象的來源

這個時候依賴注入框架就派上用場了,咱們只用專一於怎麼實現功能,對象的依賴關係和生命週期,都讓它來幫咱們管理,一個Inject,它會按照依賴關係幫咱們注入咱們須要的對象,而且它會管理好每一個對象的生命週期,在生命週期還沒結束的狀況下是不會重複new的

 

以前我看了幾個使用MVP+Dagger+Retrofit開發,而且有必定star量的開源項目,因此對比了下個人框架,有如下幾點:

  1. 使用Dagger的場景太少了,大部分只是使用Dagger注入MVP類,而且有些Retrofit都是本身new,並無使用Dagger管理,甚至有些使用一次接口就retrofit.create(ApiService.class)一次,這個本可使用Dagger將它做爲單例來調用的

  2. 有一些設計的ComponentModule徹底只是用來注入Activity和一些單例

@ActivityScope
@Component(modules = {ActivityModule.class},dependencies = {AppComponent.class})
public interface ActivityComponent {
 void inject(AActivity activity);
 void inject(BActivity activity);
 void inject(CActivity activity);
 ...
}
  • 仍是和第2條有關,若是隻有一個Module,Dagger就沒法根據每一個Presenter的須要,提供多個不一樣的Model,好比這個Presenter使用過這個接口,而且緩存已經在Model中寫好,其餘Presenter若是也要用到這個接口,就能夠直接重用這個Model,MVP最大的好處之一就是能夠重用MP

  • 有些沒有Model層,直接給Presenter注入Retrofit Api(有些是注入一個管理類,若是項目小接口少,這樣還不錯,可是有沒有想過項目一大,接口一多裏面就很是混亂),全部網絡請求邏輯在Presenter中,若是如今需求變了,須要加入緩存,就須要更改Presenter的邏輯,這樣就可能影響一些和這個功能無關的邏輯,若是有Model層,裏面持有請求網絡和緩存的功能類,這樣Presenter就不須要管,數據是從網絡仍是數據庫獲取的,Model層只用保證返回給Presenter的數據無誤,而Presenter只用專一於邏輯,這樣各自只用保證各自的職責,屏蔽細節,易擴展,出錯也好定位

 

Dagger注入MVP

Contract

這裏根據Google官方的MVP項目,能夠在Contract中定義MVP的接口,便於管理,此框架無需定義Presenter接口,因此Contract只定義Model和View的接口

 

View

通常讓 Activity 或 Fragment 實現 Contract 中定義的 View 接口,供 Presenter 調用對應方法操做 UI , BaseActivity 默認注入 Presenter ,如想使用 Presenter ,必須指定 Presenter 的範型(雖然只能夠指定一個範型,可是能夠自行生成並持有多個 Presenter ,達到重用的目的),和實現setupActivityComponent 來提供 Presenter 須要的 Component 和 Module(如這個頁面邏輯簡單並不須要 Presenter ,那就不指定範型,也不實現方法)

 

Model

Model 實現 Contract 的 Model 接口,而且繼承 BaseModel ,而後經過 IRepositoryManager 拿到須要的 Service 和 Cache 爲 Presenter 提供須要的數據(是否使用緩存請自行選擇)

 

Presenter

Presenter在MVP中的大部分的做用爲經過從Model層接口獲取數據,在調用View層接口顯示數據,首先實現BasePresenter,指定Model和View的範型,注意必定要指定Contract中定義的接口,Presenter須要的Model和View,都使用Dagger2注入,這樣即解藕又方便測試,怎麼注入?

 

MVP Module

這裏的Module提供當前業務邏輯對應的View和Model接口(Contract中定義的接口)的實現類,Model須要AppComponent中提供的RepositoryManager來實現網絡請求和緩存,因此須要經過Component依賴AppComponent來拿到這個對象

 

Dagger Scope

在上面的代碼中 ActivityScope 大量出如今 Module 和 Component 中,Dagger2 使用 Scope 限制每一個 Module 中提供的對象的生命週期, Dagger2 默認只提供一個 @Singleton Scope 即單例,本框架提供 @ActvityScope 和 @FragmentScope ,若有其餘需求請自行實現, Module 和 Component 定義相同的 Scope 後 Module 中提供的對象的生命週期會和 Component 的生命週期相綁定(即在 Component 生命週期內,如需屢次使用到 Moudle 中提供的對象,但只會調用一次@Provide 註解的方法獲得此對象)

 

Dagger注入單例

 

AppComponent

Application生命週期是和App是同樣的,因此適合提供一些單例對象,本框架使用Dagger2管理,使用AppComponent來提供全局全部的單例對象,因此須要自定義一個Application繼承自BaseApplication,便可在App的任何地方,經過BaseApplication的getAppComponent()方法,拿到AppComponent裏面聲明的全部單例對象

 

RepositoryManager

RepositoryManager 用來管理網絡請求層,以及數據庫請求層

 

AppManager(管理全部的Activity)

AppManager用於管理全部的Activity,內部持有一個含有全部存活的Activity(未調用onDestroy)的List,和一個當前在最前端的Activity(未調用onPause),AppManager封裝有多種方法,能夠很方便的對它們進行操做,也能夠在未持有AppManager的狀況下,經過EventBus遠程遙控它的全部方法,這樣咱們能夠在整個app的任何地方對任何Activity進行全局操做,好比在app請求網絡超時時讓最前端的Activity顯示鏈接超時的交互頁面(這個邏輯不用寫到當前請求的Activity裏,能夠在一個單例類裏作全局的統一操做,由於能夠隨時經過AppManager拿到當前的Activity)

 

在任意位置關閉全部的activity,得到在前臺的activity作一些操做,判斷某個activity實例是否存活

 

ActivityLifeCycle

 Application繼承activityLifeCycle管理生命週期

 

oncreate時:

activity加入appmanager

注入Dagger單例

 

onresume時:

設定當前的前臺activity

 

onDestroy時:

移除全部的activity

 

Module

ClientModule:

提供retrofit,okhttp,database單例

AppModuel:

提供application,RepositoryManager單例

 

BaseActivity

設置mainContentView

綁定butterKnife

設定toolbar

相關文章
相關標籤/搜索