本系列文章旨在概述咱們搭建 Android 應用程序架構時可能會碰到的問題。我意識到,不管實現 Android app 架構的過程多麼困難,結果證實這些必定是完成每個卓越的應用的基礎。java
每種技術都有其天然的進化。或者更確切地說,它的社區經歷了進化的過程。一個新的計算機語言或框架的早期採用者是愛好者,他們只是但願掌握技術,並儘快完成一些工做。一般,新社區規模小,在開發人員之間的知識傳遞潛力有限,也就是說,每一個人都從本身的錯誤中學習,由於沒有架構指南可用。android
你能夠說,有不少資深的傢伙在不一樣的技術上有不少的經驗,但誰也沒有時間提出標準。嗯,不必定。若是技術背後有一個強大的公司期望賺錢,他們的佈道師會告訴你這個新語言多麼酷,能夠作不少事情,容易學習,可擴展,而且能夠知足數以百萬計的用戶。程序員
微軟就常常用它的技術幹這樣的事情。另外一方面,當谷歌收購了 Android, 我真的覺得他們只是把它看成一個可有可無的項目。 若是你從 Android 誕生之時就進入 Android 的世界,你必定記得 Google 根本不在意你的那種沮喪感。 那些有額外的經驗,能力和幫助社區的意願的少數幾我的如今是 Android 的超級明星或大神 —— 譬如 Jake Wharton。數據庫
「When Google bought Android, I honestly think they treated it just as some other side project.」編程
可能你會說,你沒必要考慮太多架構和組織代碼的事情,由於(Android)Framework 幫你作了。Android 強迫你把界面放到 Activity 中,可重用的界面放到 Fragment 中, 後臺服務放到 Service 中,而且用 Broadcast Receiver 和其它組件通訊,這樣可使你的生活變得更美好,是這樣嗎?不是的。markdown
首先,有一些很好的實踐和原則確實很好,與技術(平臺)無關。例如,單一職責原則,依賴倒置原則,面向接口編程,殺死全局狀態,嘗試消滅全部狀態,等等。網絡
Framework 不多強迫你遵循原則。偏偏相反,它們以最壞的方式侵犯這些最佳實踐和原則。想一想 Context 這個你處處使用的上帝對象(God object),各類單例管理者(singleton managers),擁有生命週期的 Fragment(那是怎樣的噩夢呢),經常不能正確實現的 AsyncTask,它們吸着你 app 的血。架構
一個缺少指導的剛入行的開發者很容易造出一個怪物而不是一個 app。把它想象成一個意大利麪條般的怪物吧 —— 這是一個不錯的怪物,但不是一個好的 app。app
譯者注:意大利麪條般的怪物寓指一團亂麻的代碼框架
最後,技術(technology)和 Framework 隱藏了 app 的用途。好的,這是一個 Android app,可是一個什麼樣的 Android app 呢?新聞閱讀器?音樂播放器? 語言學習程式?天氣應用?也許是一個計劃表。若是全部的東西都打包到由 Framework 提供的類,你就說不出(這是什麼 app)。
正如 Robert Martin,也就是 Uncle Bob 說,「你的架構應該尖聲喊出(scream)app 是作什麼」,更技術一點說,業務邏輯應該清晰地分離,獨立於 Framework。
我但願已經說清楚了,你不該當依賴 Framework 來使你的代碼整潔有序,尤爲是在編寫 Android 代碼的時候。咱們很早之前就意識到這點,但是缺少拿出牛逼解決方案的經驗。架構失敗要花不少時間才能表現出來,又不能夠在項目中途改變整個架構。也不可能有時間將舊項目重構成新的、酷的、(想成爲)最佳的架構。所以,咱們採起漸進的方法,慢慢地從一個項目到另外一個項目搭建咱們的架構,從咱們的錯誤中學習。咱們認爲咱們的架構應該知足幾個目標,它們是檢驗咱們的方法的標準。好的架構應該作到:
利益相關者(在這篇文章中)是任何對你的 app 開發感興趣的人。除了開發,還有視覺設計師,交互設計師,項目經理,數據庫管理員,測試等等。
固然,你不可能以某種方式組織你的代碼,例如,交互設計師能夠打開項目並當即瞭解全部內容,甚至能夠進行一些修改。It's a unicorn.
個人意思是,你能夠以這樣一種方式組織你的代碼,那個和交互設計師對接的程序員只須要打理和交互相關的代碼。所以,全部交互被分離到那些負責交互的 classes / modules / components / whatever (組件)中,當處理 app 的交互部分時,只須要打理那些組件。
譯者注:若是暫時不能理解利益相關者,不要緊的,看完本系列第三部分你就明白了
我剛剛所說的就是一個關注點分離的例子。咱們支持這種特定的方法,由於它能很好地表達團隊組織和項目階段的配合,通常來講,你的架構也應該支持關注點分離。關注點分離或者單一職責原則是指,每個組件應該只有一個變化的緣由。
逃離真實世界這條規則,先前已經說起。咱們曾說咱們想要尖聲喊出 app 真正是作什麼的,就是那樣。咱們想要強調業務邏輯而且隱藏 Framework 的細節。這條規則應該更嚴格:不只要隱藏 Framework 的細節,並且要隱藏全部與外部世界相關的細節。
全部的骯髒的 Android 的東西,如傳感器、通知機制、屏幕細節、數據庫訪問、互聯網訪問等。
你應該儘量地對你的 app 進行單元測試,而且你的架構應該容許你這樣作。若是你不能測試全部東西,你至少應該覆蓋你的業務邏輯。與真實世界分離能夠很方便地作到這點。若是你的業務邏輯清晰地和 app 其他部分隔離,是很容易測試的。
public final class UsersActivity extends ListActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //... new ListUsers().execute(); } private final class ListUsers extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... voids) { // final SQLiteOpenHelper sqLiteOpenHelper = ... // JsonObjectRequest jsObjRequest = new JsonObjectRequest // (Request.Method.GET, url, null, new Response.Listener<JSONObject>() { // MySingleton.getInstance(this).addToRequestQueue(jsObjRequest); // showData(user); return null; } } } 複製代碼
你可能在 「上古時代」 看到過這樣的代碼。若是沒有,說明你很年輕。可是這一段代碼哪裏有問題呢?答案是哪裏都有問題。
咱們有一個 Activity 操做數據庫,訪問網絡,解析數據,切換線程以及渲染數據。全部的利益相關者都在看這一個類,沒有關注點是分離的,它是不可測試的,業務邏輯和 Android 的東西混雜在一塊兒。
譯者注:留意上圖左邊紅色的標籤。每一個標籤分別對應一條黃金法則,紅色表示不知足。SRP 是指單一職責原則,即分離關注點。
第一種方法顯然是不能工做的。咱們嘗試過的第一件事情是 MVP,或者說 model-view-presenter。每一個人都熟悉 MVP。它是最受歡迎的架構模式之一。看起來像這樣:
這裏,咱們分離了其實是 Android Fragment 的 View,咱們擁有表明咱們業務的(領域)模型,最後咱們有協調一切的 Presenter。這確定是更好的。關注點有了一些分離,利益相關者再也不那麼困惑,你也能夠寫一些單元測試了。儘管如此,因爲 Presenter 直接操做數據庫和全部一切,咱們仍然和真實世界混雜在一塊兒。Presenter 成了上帝對象。它處理模型,將數據發送到視圖,它擁有業務邏輯(業務邏輯是那些齒輪 :)),它訪問數據庫和網絡,獲取傳感器數據,等等。因此,是好了些,但能夠更好。
譯者注:黃色的標籤表示好了些
當政府不知道作什麼的時候它會作什麼?它成立一個代理機構。當開發不知道作什麼的時候他們會作什麼?他們引入一些 Manager。你不必定把它命名爲 「*Manager」 。 這些類有不少名字:uitls、helpers、fooBarBuzz-ator、等等。所以咱們引入 Manager。
說實話,這甚至有點湊效。業務邏輯包含在 Manager 中。利益相關者知道往哪看,關注點必定程度是分離的但能夠作得更好,你能夠編寫更多的測試,但你依然直接觸摸 Android ,因此你必須編寫 Android 測試用例,並預先填寫數據庫來測試業務邏輯,一個字:不爽。是的,Manager 有變成巨獸的傾向,很快就變得難以維護。你可能爭論說它不會變得更復雜,你能夠經過更簡單的架構來更快地提供代碼,但經過這種方法依然會有不少 BUG,可維護性也會遭到破壞。
譯者注:留意 Manager this 和 Manager that 之間的標籤
在本系列的第一部分,咱們經歷了搭建實際可用的 Android 架構的挑戰。良好的 Android 架構應該知足衆多利益相關者的需求,支持關注點分離,強調業務邏輯,隱藏 Framework 的細節,並使你全部的組件均可以測試。在系列的第二部分,咱們將向你展現咱們如何管理對咱們有用的功能。在此以前,你是否有如何建立合適的 Android 工做流的建議?或者你遇到了什麼問題?