Android 開發:由模組化到組件化(一)

來源:互聯網
上載者:User

標籤:技術   水平   適用於   建立   遇到   總結   功能測試   相對   取出   

在Android SDK一文中,我們談到模組化和組件化,現在我們來聊聊組件化開發背後的哪些事.最早是在廣告SDK中應用組件化,但是同樣適用於普通應用開發

以下高能,請做好心理準備,看不懂請發私信來交流.本文不推薦新手閱讀,如果你剛接觸Android開發不久,請立刻放棄閱讀本文.

模組化和組件化模組化

組件化不是個新概念,其在各行各業都一直備受重視.至於組件化什麼時候在軟體工程領域提出已經無從考究了,不過呢可以確認的是組件化最早應用於服務端開發,後來在該思想的指導下,前端開發和移動端開發也產生各自的開發方式.

在瞭解組件化之前,先來回顧下模組化的定義

Modular programming is a software design technique that emphasizes separating the functionality of a program into independent, interchangeable modules, such that each contains everything necessary to execute only one aspect of the desired functionality.

簡單來說,模組化就是將一個程式按照其功能做拆分,分成相互獨立的模組,以便於每個模組只包含與其功能相關的內容。模組我們相對熟悉,比如登入功能可以是一個模組,搜尋功能可以是一個模組,汽車的發送機也可是一個模組.

組件化

現在來看看”組件化開發”,這裡我們看一下其定義:

Component-based software engineering (CBSE), also known as component-based development (CBD), is a branch of software engineering that emphasizes the separation of concerns in respect of the wide-ranging functionality available throughout a given software system. It is a reuse-based approach to defining, implementing and composing loosely coupled independent components into systems. This practice aims to bring about an equally wide-ranging degree of benefits in both the short-term and the long-term for the software itself and for organizations that sponsor such software.

通俗點就是:組件化就是基於可重用的目的,將一個大的軟體系統按照分離關注點的形式,拆分成多個獨立的組件,已較少耦合。

咋樣一看還是非常抽象,說了這麼多好像還是不明白.什麼是組件呢?組件可以是模組、web資源,軟體包,比如汽車的發動機是一個模組,也是一個組件,再或者前端中的一個日曆控制項是一個模組,也一個組件.

模組化 vs 組件化

當你看到這的時候,想必心理一陣惡寒:模組化?組件化?到底是什麼鬼?有啥區別.
有這種感覺才是對的,模組化和組件化本質思想是一樣的,都是”大化小”,兩者的目的都是為了重用和解耦,只是叫法不一樣.如果非要說區別,那麼可以認為模組化粒度更小,更側重於重用,而組件化粒度稍大於模組,更側重於業務解耦.

組件化優缺點

組件化開發的好處是顯而易見:系統級的控制力度細化到組件級的控制力度,一個複雜系統的構建最後就是組件整合的結果.每個組件都有自己獨立的版本,可以獨立的編譯,測試,打包和部署

產品組件化後能夠實現完整意義上的按需求進行產品配置和銷售,使用者可以選擇使用那些組件,組件之間可以靈活的組建.

組態管理,開發,測試,打包,發布完全控制到組建層面,並帶來很多好處.比如一個組件小版本進行升級,如果對外提供的介面沒有發生任何變化,其他組件完全不需要再進行測試.

但是組件化的實施對開發人員和團隊管理者提出了更高水平的要求.相對傳統方式,在項目的管理和組織上難度加大,要求開發人員對業務有更深層次上的理解.

進軍Android 項目為什麼要在Android中實行組件化開發

為什麼要在Android中實行組件化開發呢,其根本原因在於業務的增長提高了項目的複雜性,為了更好的適應團隊開發,提高開發效率,實行組件化乃大勢所趨.

為了更好的協助大家理解上面這句話,我將從最早的Android 項目開發方式說起.

簡單開發模型

所謂的簡單開發模型是最基礎的開發方式,工程中沒有所謂的模組,沒有所謂的規劃,常見於初學者學習階段或者是個人學習過程所寫的demo,其結構大概如下:

不難發現,往往是在一個介面中存在著大量的商務邏輯,而商務邏輯中充斥著各種各種網路請求,資料操作等行為,整個項目中沒有所謂的模組的概念,項目組成的基本單位不是模組,而是方法級的.

關於這種開發模型沒什麼需要介紹的,我們早期都經曆過,現在除了很少非常古老的項目以及初學者練手之作,已經很少見到.

單工程開發模型

該種開發模型已經有了明確的模組劃分,並且通過邏輯上的分層呈現出較好結構,該模型最為我們所熟悉,通常用於早期產品的快速開發,團隊規模較小的情況下.該種開發模型結構如下:

隨著產品的迭代,業務越來越複雜,隨之帶來的是項目結構複雜度的極度增加,此時我們面臨著幾個問題:

  1. 實際業務變化非常快,但是工程之前的業務模組耦合度太高,牽一髮而動全身.
  2. 對工程所做的任何修改都必須要編譯整個工程
  3. 功能測試和系統測試每次都要進行.
  4. 團隊協同開發存在較多的衝突.不得不花費更多的時間去溝通和協調,並且在開發過程中,任何一位成員沒辦法專註於自己的功能點,影響開發效率.
  5. 不能靈活的對工程進行配置和組裝.比如今天產品經理說加上這個功能,明天又說去掉,後天在加上.

在面臨這些問題的前提下,我們重新來思考組件化,看看它是否能解決我們在Android 項目開發中所遇到的難題.

主工程多組件開發模型

藉助組件化這一思想,我們在”單工程”模型的基礎上,將業務層中的各業務抽取出來,封裝成相應的業務組件,將基礎庫中各部分抽取出來,封裝成基礎組件,而主工程是一個可啟動並執行app,作為各組件的入口(主工程也被稱之為殼程式).這些組件或以jar的形式呈現,或以aar的形式呈現.主工程通過依賴的方式使用組件所提供的功能.

(需要注意這是理想狀態下的結構圖,實際項目中,業務組件之間會產生通訊,也會產生依賴,關於這一點,我們在下文會談)

不論是jar還是aar,本質上都是Library,他們不能脫離主工程而單獨的運行.當團隊中成員共同參與項目的開發時,每個成員的開發裝置中必須至少同時具備主工程和各自負責組件,不難看出通過對項目實行組件化,每個成員可以專註自己所負責的業務,並不影響其他業務,同時藉助穩定的基礎組件,可以極大減少代碼缺陷,因而整個團隊可以以並行開發的方式高效的推進開發進度.

不但如此,組件化可以靈活的讓我們進行產品組裝,要做的無非就是根據需求配置相應的組件,最後生產出我們想要的產品.這有點像玩積木,通過不同擺放,我們就能得到自己想要的形狀.

對測試同學而言,能有效減少測試的時間:原有的業務不需要再次進行功能測試,可以專註於發生變化的業務的測試,以及最終的整合測試即可.

到現在為止,我們已經有效解決了”單工程開發模型”中一些問題,對於大部分團隊來說這種已經可以了,但是該模型仍然存在一些可以改進的點:每次修改依賴包,就需要重新編譯產生lib或者aar.比如說小顏同學接手了一個項目有40多個組件,在最後整合所有組件的時候,小顏同學發現其中某組件存在問題,為了定位和修改該組件中的問題,小顏同學不斷這調試該組件.由於在該模型下,組件不能脫離主工程,那麼意味著,每次修改後,小顏同學都要在漫長的編譯過程中等待.更糟糕的是,現在離上線只有5小時了,每次編譯10分鐘,為改這個bug,編譯了20次,恩….什麼也不用幹了,可以提交離職報告了

如何解決這種每次修改組件都要連同主工程一起編譯的問題?下面我們來看主工程多子工程開發模型是如何解決該問題的.

主工程多子工程開發模型

該種開發模型在”主工程多組件”開發模型的基礎上做了改進,其結構圖如下:

不難發現,該種開發模型在結構上和”主工程多組件”並無不同,唯一的區別在於:所有業務組件不再是mouble而是作為一個子工程,基礎組件可以使moudle,也可以是子工程,該子工程和主工程不同:Debug模式下下作為app,可以單獨的開發,運行,調試;Release模式下作為Library,被主工程所依賴,向主工程提供服務.

在該種模型下,當小顏同學發現某個業務組件存在缺陷,會如何做呢?比如是基礎組件2出現問題,由於在Debug模式下,基礎組件2作為app可以獨立啟動並執行,因此可以很容易地對該模組進行單獨修改,調試.最後修改完後只需要重新編譯一次整個項目即可.

不難發現該種開發模型有效減少了全編譯的次數,減少編譯耗時的同時,方便開發人員進行開發調試.

對測試同學來說,功能測試可以提前,並且能夠及時的參與到開發環節中,將風險降到最低.

到現在,我們在理論層次上講明了採用組件化開發給我們帶來的便利,空口無憑是沒令人信服的,在下面的一小節中,我們來談談如何組件化在Android中的實施過程.

組件化過程中遇到的問題組件劃分

組件化首要做的事情就是劃分組件.如何劃分並沒有一個確切的標準,我建議早期實施組件化的時候,可以以一種”較粗”的粒度來進行,這樣左右的好處在於後期隨著對業務的理解進行再次細分,而不會有太大的成本.當然,我建議劃分組件這一工作有團隊架構人員和業務人員協商定製.

子工程工作方式切換

在”主工程多子工程模型”中,我們提到子工程在Debug模式下做為單獨的Application運行,在Release模式下作為Library運行,如何去動態修改子工程的運行模式呢?我們都知道採用Gradle構建的工程中,用apply plugin: ‘com.android.application‘來標識該為Application,而apply plugin: ‘com.android.library‘標誌位Library.因此,我們可以在編譯的是同通過判斷構建環境中的參數來修改子工程的工作方式,在子工程的gradle指令碼頭部加入以下指令碼片段:

if (isDebug.toBoolean()) {    apply plugin: ‘com.android.application‘} else {    apply plugin: ‘com.android.library‘}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

除此之外,子工程中在不同的運行方式下,其AndroidMainifest.xml也是不相同的,需要為其分別提供自己AndroidManifest.xml檔案:在子工程src目錄下(其他位置建立)建立兩個目錄,用來存放不同的AndroidManifest.xml,比如這裡我建立了debug和release目錄

接下來同樣需要在該子工程的gradle構建指令碼中根據構建方式制定:

android {    sourceSets {        main {            if(isDebug.toBoolean()) {                manifest.srcFile ‘src/debug/AndroidManifest.xml‘            } else {                manifest.srcFile ‘src/release/AndroidManifest.xml‘            }        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
組件通訊與組件依賴

在”主工程多組件”這種理想模型下業務組件是不存在相互連信和依賴的,但現實卻是相反的,如:

這裡,業務組件1和業務組件3同時向業務組件2提供服務,即業務組件2需要同時依賴業務組件3和業務組件1.

現在我們再來看一種更糟糕的情況:

由此看來,在業務複雜的情況下,組件與組件之間的相互依賴會帶來兩個問題:

  • 重複依賴:比如可能存在業務組件3依賴業務組件1,而業務組件2又依賴業務組件3和業務組件1,此時就導致了業務組件1被重複依賴.
  • 子系統通訊方式不能依靠傳統的顯.在該種模型下,使用顯將導致組件高度耦合.比如業務組件2依賴業務組件1,並通過顯的方式進行通訊,一旦業務組件1不再使用,那麼業務組件2中使用現實意圖的地方會出現錯誤,這顯然與我們組件化的目的背道而馳.
解決組件通訊

先來解決業務組件通訊問題.當年看到上面那張複雜的組件通訊圖時,我們不難想到作業系統引入匯流排機制來解決裝置掛載問題,同樣,借用匯流排的概念我們在工程添加”組件匯流排”,用於不同組件間的通訊,此時結構如下:

所有掛載到組件匯流排上的業務組件,都可以實現雙向通訊.而通訊協定和HTTP通訊協定類似,即基於URL的方式進行.至於實現的方式一種可以基於系統提供的隱式意圖的方式,另一種則是完全自行實現組件匯流排.這篇文章不打算在此不做詳細說明了.

解決重複依賴

對於採用aar方式輸出的Library而言,在構建項目時,gradle會為我們保留最新版本的aar,換言之,如果以aar的方式向主工程提供提供依賴不會存在重複依賴的問題.而如果是直接以project形式提供依賴,則在打包過程中會出現重複的代碼.解決project重複依賴問題目前有兩種做法:1.對於純程式碼工程的庫或jar包而言,只在最終項目中執行compile,其他情況採用provider方式;2.在編譯時間檢測依賴的包,已經依賴的不再依賴

資源id衝突

在合并多個組件到主工程中時,可能會出現資源引用衝突,
最簡單的方式是通過實現約定資源首碼名(resourcePrefix)來避免,需要在組件的gradle指令碼中配置:

andorid{    ...    buildTypes{        ...    }    resourcePrefix "moudle_prefix"}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

一旦配置resourcePrefix,所有的資源必須以該首碼名開頭.比如上面配置了首碼名為moudle_prefix,那麼所有的資源名都要加上該首碼,如:mouble_prefix_btn_save.

組件上下文(Context)

最後需要注意在Debug模式下和Release模式下,所需要的Context是否是你所希望的,以避免產生強轉異常.

結束語

最早接觸組件化這個概念是在從事廣告SDK工作中,最近陸續續的做了一些總結,因此有了這篇關於”組件化開發”的文章.另外,組件化開發不是銀彈,並不能完全解決當前業務複雜的情況,在進行項目實施和改進之前,一定要多加考量.

敬請期待第二篇,我們將在第二篇內介紹如何對項目實施組件化.

Android 開發:由模組化到組件化(一)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.