1. 程式人生 > >[轉載] 一種更清晰的Android架構

[轉載] 一種更清晰的Android架構

一種更清晰的Android架構

過去幾個月以來,通過在Tuenti網站上與@pedro_g_s和@flipper83(安卓開發兩位大牛)進行友好討論之後,我決定寫這篇關於架構安卓應用的文章。

我寫這篇文章的目的是想把我在過去幾個月體悟到的小方法以及在調查和應用中學到的有用的東西分享給大家。

入門指南

大家都知道要寫一款精品軟體是有難度且很複雜的:不僅要滿足特定要求,而且軟體還必須具有穩健性,可維護、可測試性強,並且能夠靈活適應各種發展與變化。這時候,“清晰架構”就應運而生了,這一架構在開發任何軟體應用的時候用起來非常順手。

這個思路很簡單:簡潔架構 意味著產品系統中遵循一系列的習慣原則:

  • 框架獨立性
  • 可測試
  • UI獨立性
  • 資料庫獨立性
  • 任何外部代理模組的獨立性

我們並不要求一定要用四環結構(如圖所示),這只是一個示例圖解,但是要考慮的是依賴項規則:原始碼依賴項只能向內指向,內環裡的所有項不能瞭解外環所發生的東西。

以下是更好地理解和熟悉本方法的一些相關詞彙:

  • Entities:是指一款應用的業務物件
  • Use cases:是指結合資料流和實體中的用例,也稱為Interactor
  • Interface Adapters: 這一組介面卡,是負責以最合理的格式轉換用例(use cases)和實體(entities)之間的資料,表現層(Presenters )和控制層(Controllers ),就屬於這一塊的。
  • Frameworks and Drivers: 這裡是所有具體的實現了:比如:UI,工具類,基礎框架,等等。

想要更具體,更生動豐富的解釋,可以參考這篇文章或者這個視訊

場景

我會設定一個簡單的場景來開始:建立一個簡單的小app,app中顯示從雲端獲取的一個朋友或使用者列表。當點選其中任何一個時,會開啟一個新的視窗,顯示該使用者的詳細資訊。這裡我放了一段視訊,大家看看這個視訊 (需翻牆)大概就可以對我所描述的東西瞭解個大概了。

Android應用架構

這一物件遵循關注分離原則,也就是通過業務規則讓內環操作對外環事物一無所知,這樣一來,在測試時它們就不會依賴任何的外部元素了。
要達到這個目的,我的建議就是把一個專案分成三個層次,每個層次擁有自己的目的並且各自獨立於堆放運作。
值得一提的是,每一層次使用其自有的資料模型以達到獨立性的目的(大家可以看到,在程式碼中需要一個數據對映器來完成資料轉換。如果你不想把你的模型和整個應用交叉使用,這是你要付出的代價)。

以下是圖解,大家感受下:



注:我並沒有使用任何的外部庫(除了用於json資料句法分析的gson和用於測試的junit, mockito, robolectric和espresso以外)。原因是它可以使這個示例更清晰。總之,在儲存磁碟資料時,記得加上ORM、依賴注入框架或者你熟悉的任何工具或庫,這些都會帶來很大幫助。(記住:重複製造輪子可不是明智的選擇)

表現層 (Presentation Layer)

表現層在此,表現的是與檢視和動畫相關的邏輯。這裡僅用了一個Model View Presenter(下文簡稱MVP),但是大家也可以用MVC或MVVM等模式。這裡我不再贅述細節,但是需要強調的是,這裡的fragment和activity都是View,其內部除了UI邏輯以外沒有其他邏輯,這也是所有渲染的東西發生的地方。
本層次的Presenter由多個interactor(用例)組成,Presenter在 android UI 執行緒以外的新執行緒裡工作,並通過回撥將要渲染到View上的資料傳遞回來。


如果你需要一個使用MVP和MVVM的Effective Android UI典型案例,可以參考我朋友Pedro Gómez的文章。

領域層 (Domain Layer)

這裡的業務規則是指所有在本層發生的邏輯。對於Android專案來說,大家還可以看到所有的interactor(用例)實施。這一層是純粹的java模組,沒有任何的Android依賴性。當涉及到業務物件時,所有的外部元件都使用介面。


資料層 (Data Layer)

應用所需的所有資料都來自這一層中的UserRepository實現(介面在領域層)。這一實現採用了Repository Pattern,主要策略是通過一個工廠根據一定的條件選取不同的資料來源。
比如,通過ID獲取一個使用者時,如果這個使用者在快取中已經存在,則硬碟快取資料來源會被選中,否則會通過向雲端發起請求獲取資料,然後儲存到硬碟快取。
這一切背後的原理是由於原始資料對於客戶端是透明的,客戶端並不關心資料是來源於記憶體、硬碟還是雲端,它需要關心的是資料可以正確地獲取到。


注:在程式碼方面,出於學習目的,我通過檔案系統和Android preference實現了一個簡單、原始的硬碟快取。請記住,如果已經存在了能夠完成這些工作的庫,就不要重複製造輪子。

錯誤處理

這是一個長期待解決的討論話題,如果大家能夠分享各自的解決方案,那真真是極好的。
我的策略是使用回撥,這樣的話,如果資料倉庫發生了變化,回撥有兩個方法:onResponse()和onError(). onError方法將異常資訊封裝到一個ErrorBundle物件中: 這種方法的難點在於這其中會存在一環扣一環的回撥鏈,錯誤會沿著這條回撥鏈到達展示層。因此會犧牲一點程式碼的可讀性。另外,如果出現錯誤,我本來可以通過事件匯流排系統丟擲事件,但是這種實現方式類似於使用C語言的goto語法。在我看來,當你訂閱多個事件時,如果不能很好的控制,你可能會被弄得暈頭轉向。

測試

關於測試方面,我根據不同的層來選擇不同的方法:

  • 展示層 ( Presentation Layer) : 使用android instrumentation和 espresso進行整合和功能測試
  • 領域層 ( Domain Layer) : 使用JUnit和Mockito進行單元測試;
  • 資料層 ( Data Layer) : 使用Robolectric ( 因為依賴於Android SDK中的類 )進行整合測試和單元測試。

程式碼展示

我猜你現在在想,扯了那麼久的淡,程式碼究竟在哪裡呢? 好吧,這就是你可以找到上述解決方案的github連結。還要提一點,在資料夾結構方面,不同的層是通過以下不同的模組反應的:

  • presentation: 展示層的Android模組
  • domain: 一個沒有android依賴的java模組
  • data: 一個數據獲取來源的android模組。
  • data-test: 資料層測試,由於使用Robolectric 存在一些限制,所以我得再獨立的java模組中使用。

結論

正如 Bob大叔 所說:“Architecture is About Intent, not Frameworks” ,我非常同意這個說法,當然了,有很多不同的方法做不同的事情(不同的實現方法),我很確定,你每天(像我一樣)會面臨很多挑戰,但是遵循這些方法,可以確保你的應用會:

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

相關推薦

[轉載] 清晰Android架構

一種更清晰的Android架構 過去幾個月以來,通過在Tuenti網站上與@pedro_g_s和@flipper83(安卓開發兩位大牛)進行友好討論之後,我決定寫這篇關於架構安卓應用的文章。 我寫這篇文章的目的是想把我在過去幾個月體悟到的小方法以及在調查和應用中學到的有用的東西分享給大家。 入門指南 大家都

清晰Android 架構

過去幾個月以來,通過在Tuenti網站上與@pedro_g_s和@flipper83(安卓開發兩位大牛)進行友好討論之後,我決定寫這篇關於架構安卓應用的文章。 我寫這篇文章的目的是想把我在過去幾個月體悟到的小方法以及在調查和應用中學到的有用的東西分享給大家

Android指紋識別API講解,好的使用者體驗

 我發現了一個比較怪的現象。在iPhone上使用十分普遍的指紋認證功能,在Android手機上卻鮮有APP使用,我簡單觀察了一下,發現Android手機上基本上只有支付寶、微信和極少APP支援指紋認證功能,就連銀行和金融類的應用都基本不支援,甚至很多開發者都不知道Androi

Android系統下解決音訊underrun噪聲問題的優方法

【問題概要】     上一次我介紹了一種 Android 系統下發生音訊 underrun 問題的解決方法(參見《記一次Android系統下解決音訊UnderRun問題的過程》),這之後平靜了一段時間,測試組同事也沒有再報告相關的噪聲問題。     但就在前 2 天,測試組

kotlin, 新的android平臺一級開發語言

程序 16px 語法 jvm ava lin 使用 ide 擁有 最近看到一則科技新聞, 大致內容是google將kotlin語言作為android應用開發的一級語言, 與java並駕齊驅, 這是一個開發界的大事件大新聞, 連google的親兒子go語言也沒有這

UE4 VR中比較清晰的UI制作方式

ack 比較 不支持 cube live wid OS 方式 暫停   在進行UE4 VR 制作工程中,因為有很多UI元素要呈現,例如字幕、暫停界面等等,但使用3D Widget總是各種不如意,尤其在呈現文字的時候,文字很很虛並且在人物高速運動時,3D UI元素會劇烈抖動,

貝葉斯優化: 好的超引數調優方式

簡介 本文受 淺析 Hinton 最近提出的 Capsule 計劃 啟發,希望以更通俗的方式推廣機器學習演算法,讓有數學基礎和程式設計能力的人能夠樂享其中。 目前人工智慧和深度學習越趨普及,大家可以使用開源的Scikit-learn、TensorFlow來實現機器學習模型,甚至參加Kaggl

RAP高效的前後端介面對接解決方案

RAP一種更高效的前後端介面對接解決方案  Rico_wang 關注 2017.11.28 21:58* 字數 1448 閱讀 14348評論 12喜歡 14 我在向小夥伴推薦RAP的時候,有的小夥伴會覺得這個是個玩好意,幫助很大,而另一部

高效的android雙擊退出(可擴充套件多擊)

參考Google,安卓手機中在檢視安卓系統版本的地方,三擊或者多擊會出現彩蛋,可以借鑑其原始碼進行實現。 //利用陣列來儲存時間     long[] mHits = new long[3];     @Override     pub

MVP+Dagger2+Retrofit實現清晰架構

這個架構已經有不少文章介紹了,今天打算自己實踐下。 MVP概念不多說了 相關介紹已經很多了 Dagger2:依賴注入框架,用來解決依賴 除了基本依賴 mvp的V–>P–>M的之間依賴也輕鬆解決 方便不少 Retrofit:用來解決M的Res

OpenCL:異構計算架構

轉載 王博部落格,https://www.cnblogs.com/wangshide/archive/2012/01/07/2315830.html OpenCL:一種異構計算架構 目錄 1 摘要 2 為什麼需要OpenCL? 3 OpenCL架構

簡單的求最小平方均值函式(MSE)的方法 -- 梯度下降法。

在上一篇部落格中我們通過解析解法算出來了 但是上面公式中的對稱陣是N維乘以N維的,複雜度為O(n*n*n),雖然很精準但是很慢。 為此我們引入梯度下降法 我們首先大致畫出MSE的影象,MSE是一個開口向下,有最小值的凸函式,它的影象如下圖。

C、C++實現的智慧資料管理架構

之前研究STL相關結構的時候,發現STL系列的map、list、vector等設計有以下缺陷: 1.迭代刪除節點的情況下只可以刪除一個節點(不包括清除所有節點的情況); 2.在多執行緒情況下需要加鎖或臨界區等形式同步物件結構資訊,這種情況屬於當前大部分系統設計的

python裝飾器,容易理解的方式

裝飾器的策略可以這樣來概括,它是對原有函式封閉性的保持,又對原有函式進行擴充套件;就是說對你原有的程式碼不做修改,保證其功能模組不發生改變,在原有函式的基礎上,再加一層,對原有函式進行擴充套件;假如說有這樣一件事情:def printout(num):    print "T

簡單的Android 中全域性更換字型的方法

在我們開發Android程式的時候通常會遇到更改全域性字型的需求,我目前能想到的解決方案有三種,下面我們來進行逐一分析: 第一種方式就是自定義控制元件,毫無疑問這個一定能解決我們的問題,只需要把我們之前用的控制元件換成我們自定義的控制元件就好,缺點是如果是多種控制元件我們就

Oracle知識點彙總(清晰透徹,持續更新中!

一.sql語言類別。1.      DDL(資料定義語言):create(建立),alter(修改)和drop(刪除)命令。2.      DML(資料操縱語言):insert(插入),select(查詢),delete(刪除),update(更新)命令。3.      TC

常見的微控制器架構實現方式說明

#define num 3 //任務的數量,和func_x中形引數量需對應 typedef void (*p)(void); //定義一個函式指標 void func_1(void); //對你的任務1進行宣告 void func_2

優雅的Flutter Dialog解決方案

# 前言 系統自帶的Dialog實際上就是Push了一個新頁面,這樣存在很多好處,但是也存在一些很難解決的問題 - **必須傳BuildContext** - loading彈窗一般都封裝在網路框架中,多傳個context引數就很頭疼;用fish_redux還好,effect層直接能拿到context

Android應用啟動優化:DelayLoad的實現和原理(下篇)(轉載

我們使用第三種方法來實現延遲載入。不過上一篇寫的比較簡單,只是講解了如何去實現,這一篇就來講一下為何要這麼做,以及這麼做後面的原理。 其中會涉及到一些 Android 中的比較重要的類,以及 Activity 生命週期中比較重要的幾個函式。 其實這個其中的原理比較簡單,不過要弄清楚其實現的過程,還是一件蠻好

android 快速開發()抽象類的使用:使業務邏輯清晰

抽象類的使用:使業務邏輯更清晰 一、abstract修飾符         abstract修飾符可以用於類、方法、屬性、事件和索引指示器(indexer),表示其為抽象成員,抽象方法是沒有方法體的方法。         abstract 不可以和static、virtu