1. 程式人生 > >Architecting Android…The clean way?

Architecting Android…The clean way?

維護 dap 是我 不同的 ack 註意 jvm 取數 strong

Architecting Android…The clean way?


過去幾個月,與@pedro_g_s@flipper83 (順嘴說一下這兩位是android開發大牛)兩位同行在Tuenti 站點上友好的討論之後。我覺得這是一個寫一篇關於android應用架構的文章的好時機


寫這篇文章的目的是想給大家展現一些我在這幾個月所想的加上從研究和實施中學到的一些小方法。

入門指南

我們知道寫一款有品質的軟件是困難和復雜的: 不僅要滿足要求,同一時候也是健壯的、可維護的、可測試的。並且足夠靈活適應擴展和變化。這時 “清晰架構” 就出現了,並且可能是一個開發不論什麽軟件應用的好方法。

這個思路非常easy:清晰架構表示產品系統遵循一組實踐原則:

  • 框架獨立.
  • 可測試性.
  • UI獨立.
  • 數據庫獨立.
  • 不論什麽外部代理模塊獨立.

技術分享

不一定非要使用四環結構 (如圖所看到的),由於這僅僅是一個原理圖,可是你應該考慮依賴原則: 源代碼依賴僅僅能向內指向,而且內核中的全部項不能了解不論什麽外環的東西。

下面是一些相關的詞匯用一個更好的方式

熟悉和理解這些方法:

  • Entities: 應用的業務對象。
  • Use Cases: 結合業務對象的數據流入流出的用例. 相同被稱為Interactors。

  • Interface Adapters: 這組適配器以最合適的格式轉換用例和業務對象之間的數據。Presenters(表現層) 和 Controllers(控制層)就屬於這裏。
  • Frameworks and Drivers: 這裏是詳細的實現:UI。工具類, 框架,等等。

想要更好更生動的解釋,參考這篇文章 或 視頻。

我們的場景

我會用一個簡單的情景讓一切開始:創建一個簡單的APP用來顯示從雲端獲取的朋友列表和用戶檢索。當點擊它們的時候。一個新的界面為用戶顯示具體信息。


我放了個視頻在這裏。這樣你對我所說的有個大概的映像:

Android 架構

目標是 分離關註點。讓業務規則對外環事物一無所知,因此,它們在被測試時不須要依賴其他外部元素。
要實現這個目標,我的 建議是將項目分為三層,每個都有自己的目的而且和其他層分開工作。
值得一提的是,每一層都有自己的數據模型以達到這樣的獨立性(你會在看到在代碼中須要一個數據映射來完畢數據轉換,這須要付出一點代價,假設你不想把你的模型和整個應用交叉使用)。
這是圖示,你能夠感受一下:

技術分享

註意: 我沒有使用不論什麽外部庫(除了用於json數據的解析的gson和用來測試的junit、mockito、robolectric 和espresso)。 原因是它能夠使這個樣例更清晰。

不管怎樣不要猶豫加入ORMs存儲數據、依賴註入框架或者你熟悉的不論什麽類庫,這些都會讓你變得更輕松。(記住反復造輪子是不明智的)。

Presentation Layer (表現層)

這裏, 表現的是邏輯和視圖動畫的關聯。 這裏用了一個Model View Presenter (下稱MVP)。可是你也能夠用其他不論什麽模式。像MVC 或者 MVVM。 我不會在這裏具體描寫敘述它們,可是這裏 fragments and activities 不過views,它們內部除了UI邏輯沒有其他邏輯, 這也是全部渲染發生的地方。

在這層的Presenters 由多個 interactors (用例) 組成,在android UI線程之外的新線程運行job,並通過回調將要渲染到view的數據取回。

技術分享

假設你須要一個使用MVP或者MVVM Effective Android UI炫酷的樣例,能夠看看我的朋友 Pedro Gómez 所做的。

Domain Layer (領域層)

業務規則定義:全部的邏輯發生在這一層。 對於android項目,你也會看到全部的 interactors (用例) 在這裏實現。


這一層是一個純java的模塊,沒有不論什麽android依賴。

全部的外部組件使用接口訪問業務對象。

技術分享

Data Layer (數據層)

應用須要的全部數據來自這一層,通過UserRepository實現(這個接口在 domain layer),使用了 Repository Pattern作為策略, 通過一個 factory 類,依據一定條件下選擇不同的數據源。
比如: 通過ID獲取用戶時。假設這個用戶在緩存中已經存在。則硬盤數據會被選中,否則 會從雲端獲取數據並保存在本地磁盤。


這一切背後的理念是數據源對client是透明的。 client不關心數據來源於內存、磁盤或者雲端。它僅僅關系數據會到達和被獲取到。

技術分享

註意: 出於學習的目的,這裏我實現了一個很easy的代碼,使用文件系統和android preferences 實現原始磁盤緩存,再次,假設已經存在能出色完畢這些工作的類庫,SHOULD NOT REINVENT THE WHEEL(不要反復造輪子)

Error Handling (錯誤處理)

這是一個長期值得討論的主題。假設你能夠分享你的解決方式那真實太好了。


我的策略是使用回調callbacks, 因此。 假如數據倉庫發送改變。回調callback有兩個方法 onResponse()onError(). 最後封裝異常的類叫 “ErrorBundle”: 這樣的方法會帶來一些困難,由於有一個回調鏈一個接一個。直到錯誤到表現層呈現。

可讀性會有一點犧牲。


還有一方面。 假設出現錯誤,我使用event bus 系統拋出錯誤的事件。可是這類解決方式類似 GOTO,在我看來,當你訂閱多個事件但不能非常好的控制。你可能會懵掉。

Testing(測試)

關於測試。我依據不同的層選擇了幾個解決方式:

  • Presentation Layer(展示層): 使用android instrumentation 和 espresso 進行集成和功能測試。

  • Domain Layer(領域層): 使用JUnit 加 mockito 進行單元測試。

  • Data Layer(數據層): 使用Robolectric (這一層有android依賴) 加junit 加 mockito 進行集成和單元測試。

代碼展示

我猜你在想代碼在那裏? 好吧,這就是我上面講到內容的github連接。

關於文件夾結構。提醒一下,不同的層使用模塊來表示:

  • presentation: 是一個android模塊代表展示層。
  • domain: 是一個沒有android依賴的java模塊。
  • data: 是一個android模塊,全部數據的獲取來源。
  • data-test: 數據層測試。因為使用Robolectric有一些限制問題,我不得不使用一個單獨的模塊。

結論

正如Bob大叔所說,“Architecture is About Intent, not Frameworks” 我全然統一這個說法。當然有很多不同的方式做這些事情(不同的實現方式),我非常確信每天你(像我)一樣會面臨非常多挑戰,可是使用上面的方法。能夠確保你的應用會:

  • 易維護.
  • 易測試.
  • 高內聚.
  • 低耦合.

最後我強力推薦你去實踐一下,分享你的結果和經驗。或許你會找到更好的方法:我們都知道持續改進 總是一個好的積極的事情。
我希望這篇文章對你有幫助,相同歡迎反饋不允許見。

Source code

  1. Clean architecture github repository – master branch
  2. Clean architecture github repository – releases

Further reading:

  1. Architecting Android..the evolution
  2. Tasting Dagger 2 on Android
  3. The Mayans Lost Guide to RxJava on Android
  4. It is about philosophy: Culture of a good programmer

Links and Resources

  1. The clean architecture by Uncle Bob
  2. Architecture is about Intent, not Frameworks
  3. Model View Presenter
  4. Repository Pattern by Martin Fowler
  5. Android Design Patterns Presentation

Architecting Android…The clean way?