Android MVP 使用教程

原文地址:

http://engineering.remind.com/android-code-that-scales/

Demo

https://github.com/remind101/android-arch-sample

寫一個Hello World程序總是很簡單的,它的代碼總是很簡單、整齊的,SDK完全可以滿足我們的需求。但是,如果你在開發過複雜的Android app,你應該清楚,生產環境的代碼往往不是這樣。你需要不斷的在已經很複雜的Activity 的onCreate 方法裏面去添加if 語句去解決app在某個設備奔潰的問題,或者添加一些額外的業務邏輯。
我們每兩週就會需要添加一些新的需求,爲了能夠維持產品開發的速度和質量,我們需要讓我們的代碼簡單,可維護,耦合性低,容易測試。使用MVP架構模式可以幫助我們實現這個需求,讓我們能夠把精力集中到業務邏輯上面。MVP,全稱Model-View-Presenter,是一種提升分離交互關係的多功能模式,和其他的模式有些輕微的不同。這篇文章的目標不是其描述MVP與其他模式的區別,而是展示如何把它應用到我們Android應用開發過程中,讓我們的app受益。

Android 原有模式

Android 設計的分層是這樣的,Model 層是實體類,View層是XML佈局,Controller層是Activity,Fragment。理論上,這種模式工作得很好,但是,當你的app變得複雜,那麼在你的Controller裏面有大量的View代碼,因爲你需要處理數據綁定,動畫,輸入檢查,事件監聽,當然,還包括你的業務邏輯的代碼。如果這些複雜的界面放在List或者Grid中,那情況就更壞了,Adapter不僅僅包含着View層和Controller層的代碼,而且需要把它們當集合維護,這些模塊都是高度耦合的,很難去維護和測試。

MVP模式

MVP 提供了一種方法,可以分離出冗長的控件顯示和UI交互的Android代碼,放到View層中,把業務邏輯的的代碼放到Presenter中。Android中實現MVP方法的是,把Activity和Fragment看做是View層,用一個輕量級的Presenter去控制。最關鍵的地方是確立每一層的職責,並且使它們的接口規範化。下面是一些分層的規則:

View(Activity or Fragment)層的職責:

  • 初始化Presenter,綁定,和解綁Presenter
  • 通知Presenter 有關生命週期的方法
  • 通知Presenter輸入事件
  • 初始化View,爲View綁定數據
  • 動畫
  • 事件跟蹤
  • 界面跳轉

Presenter職責:

  • 加載實體數據
  • 持有model 和view 的引用
  • 處理數據,並交給View層顯示
  • 和數據庫,網絡交互
  • 處理UI事件

下面是View層和Presenter層的接口示例:

View:

interface MessageView { 
// View methods should be directives, as the View is just executing orders from the Presenter. 
// Methods for updating the view 
void setMessageBody(String body); 
void setAuthorName(String name);
void showTranslationButton(boolean shouldShow); 
// Navigation methods 
void goToUserProfile(User user);
}

Presenter:

interface MessagePresenter { 
// Presenter methods should mostly be callbacks, as the View is reporting events for the
// Presenter to evaluate 
// Lifecycle events methods 
void onStart();
// Input events methods 
void onAuthorClicked();

void onThreeFingersSwipe();
}

下面是一些關於這些接口的討論:

  • 更新View的方法必須是簡單的,並且作用在一個目標view上面,這比一個setMessage方法去更新所有的view好。因爲決定哪個信息放到view上面屬於業務邏輯,應該放到Presenter中去處理,例如,當作者就是當前用戶時,你想顯示”你”代替用戶名顯示到view上面,着屬於業務邏輯。
  • Presenter中的生命週期方法沒有必要完全和Activity或者Fragment中的生命週期方法去匹配,只實現需要做處理的相關方法。
  • View監聽到點擊事件時先調用Presenter中的onAuthorClicked ,然後Presenter再調用goToAuthorProfile,不能在View中調用goToAuthorProfile()方法,因爲決定去profile屬於業務邏輯,應該放在Presenter中處理。

在MVP規則中,你的Presenter層的代碼包含了Android Framework中的代碼,而不是純Java,那麼你一定是某個地方寫錯了。同樣,如果你的View層的代碼持有Model層的引用,那麼也是錯誤的。

在測試中,大部分需要測試的代碼應該在Presenter中,最大的好處是這些代碼不需要Android環境去運行,因爲Presenter只持有View的引用,沒有Android 相關代碼的實現。這意味着我們能模擬一個View的接口,寫純JUnits測試,確保業務邏輯運行正確

List列表

到目前爲止,我們猜想View層是Activity和Fragment,其實使用ViewHolder(不管是RecyclerView.ViewHolder還是List的ViewHolder )實現View的接口也可以正確的工作,在Adapter中,你只需要實現一些簡單的邏輯,包括綁定和解綁Presenter。假設你的界面上有一個消息列表,一個加載的進度條,和數據爲空時的界面,那麼應該向下面這樣分離:

  • list 的Presenter 負責加載消息邏輯,展示消息 list/empty/loading的邏輯
  • Fragment或者Activity負責 消息 list/empty/loadingView的顯示
  • Adapter負責映射Message Presenters 和ViewHolder
  • message的 Presenter 負責單條消息的邏輯
  • ViewHolder 負責單條消息的顯示

所有的組成元素都是低耦合的,非常容易單獨測試。
並且,當你有一個界面展現消息列表,一個界面展示消息詳情,那麼你可以重用相同的Presenter,只要實現兩個不同的View接口(一個是VIewHolder,一個是Fragment)。同樣的,View的接口可以被自定義view實現,這樣可以重用自定義控件。

MVP 和配置改變

如果你開發過Android App,那麼你應該在知道支持設備旋轉和配置改變是一件痛苦的事情:

  • 每次在使用Activity或者Fragment時,就必須考慮,如果設備旋轉,應該怎麼處理,是否需要保存什麼數據。
  • 在後臺線程處理長時間任務時,最容易犯的錯誤就是持有Activity或者是Fragment的引用,必須要等到任務結束時才能釋放,這樣有可能會導致內存泄露。

使用MVP可以正確的處理這一切而你不需要考慮它,因爲Presenter 對象沒有持有UI強引用,它們都是輕量級的並且可以在方向改變時保留實例。因爲Presenter 持有了Model的引用和View的狀態,在配置文件改變時,它能重新創建。
下面是假設用戶下載時,方向旋轉手機屏幕,MVP怎樣工作:

  1. Activity第一次被創建,會創建新的Presenter,綁定到當前Activity。
  2. 點擊下載按鈕,長時間任務開始在Presenter中運行。
  3. 旋轉屏幕,Presenter和Activity解綁,第一個Activity實例被回收,Presenter實例仍然保留,下載任務仍然運行。
  4. 第二個Activity實例被創建,綁定原來的Presenter。
  5. 下載任務完成,Presenter更新View。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章