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

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

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


模塊化和組件化

模塊化

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

在瞭解組件化以前,先來回想下模塊化的定義bash

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.markdown

簡單來講,模塊化就是將一個程序依照其功能作拆分,分紅相互獨立的模塊,以便於每個模塊僅僅包括與其功能相關的內容。模塊咱們相對熟悉,比方登陸功能可以是一個模塊,搜索功能可以是一個模塊,汽車的發送機也但是一個模塊.網絡

組件化

現在來看看」組件化開發」,這裏咱們看一下其定義:架構

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.app

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

咋樣一看仍是很是抽象,說了這麼多好像仍是不明白.什麼是組件呢?模塊化

組件可以是模塊、web資源,軟件包,比方汽車的發動機是一個模塊,也是一個組件,再或者前端中的一個日曆控件是一個模塊,也一個組件.

模塊化 vs 組件化

當你看到這的時候,想必心理一陣惡寒:模塊化?

組件化?到底是什麼鬼?有啥差異.
有這樣的感受纔是對的,模塊化和組件化本質思想是同樣的,都是」大化小」,二者的目的都是爲了重用和解耦,僅僅是叫法不同.假設非要說差異,那麼可以以爲模塊化粒度更小,更側重於重用,而組件化粒度稍大於模塊,更側重於業務解耦.

組件化優缺點

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

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

配置管理,開發,測試,打包,公佈全然控制到組建層面,並帶來很是多優勢.比方一個組件小版本號進行升級,假設對外提供的接口沒有發生不論什麼變化,其它組件全然不需要再進行測試.

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


進軍Android 項目

爲何要在Android中實行組件化開發

爲何要在Android中實行組件化開發呢,其根本緣由在於業務的增加提升了項目的複雜性,爲了更好的適應團隊開發,提升開發效率,實行組件化乃大勢所趨.

爲了更好的幫助你們理解上面這句話,我將從最先的Android 項目開發方式提及.

簡單開發模型

所謂的簡單開發模型是最基礎的開發方式,project中沒有所謂的模塊,沒有所謂的規劃,常見於剛開始學習的人學習階段或者是我的學習過程所寫的demo,其結構大概例如如下:
這裏寫圖片描寫敘述

不難發現,每每是在一個界面中存在着大量的業務邏輯,而業務邏輯中充斥着各類各類網絡請求,數據操做等行爲,整個項目中沒有所謂的模塊的概念,項目組成的基本單位不是模塊,而是方法級的.

關於這樣的開發模型沒什麼需要介紹的,咱們早期都經歷過,現在除了很是少很是古老的項目以及剛開始學習的人練手之做,已經很是少見到.

單project開發模型

該種開發模型已經有了明白的模塊劃分,並且經過邏輯上的分層呈現出較好結構,該模型最爲咱們所熟悉,通常用於早期產品的高速開發,團隊規模較小的狀況下.該種開發模型結構例如如下:
這裏寫圖片描寫敘述

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

  1. 實際業務變化很是快,但是project以前的業務模塊耦合度過高,牽一髮而動全身.
  2. 對project所作的不論什麼改動都必需要編譯整個project
  3. 功能測試和系統測試每次都要進行.
  4. 團隊協同開發存在較多的衝突.不得不花費不少其它的時間去溝通和協調,並且在開發過程當中,不論什麼一位成員沒辦法專一於本身的功能點,影響開發效率.
  5. 不能靈活的對project進行配置和組裝.比方今天產品經理說加上這個功能,明天又說去掉,後天在加上.

在面臨這些問題的前提下,咱們又一次來思考組件化,看看它可否解決咱們在Android 項目開發中所遇到的難題.

主project多組件開發模型

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

這裏寫圖片描寫敘述

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

不管是jar仍是aar,本質上都是Library,他們不能脫離主project而單獨的執行.當團隊中成員共同參與項目的開發時,每個成員的開發設備中必須至少同一時候具有主project和各自負責組件,不難看出經過對項目實行組件化,每個成員可以專一本身所負責的業務,並不影響其它業務,同一時候藉助穩定的基礎組件,可以極大下降代碼缺陷,於是整個團隊可以以並行開發的方式高效的推動開發進度.

不但如此,組件化可以靈活的讓咱們進行產品組裝,要作的無非就是依據需求配置對應的組件,最後生產出咱們想要的產品.這有點像玩積木,經過不一樣擺放,咱們就能獲得本身想要的形狀.

對測試同窗而言,能有效的下降測試的時間:原有的業務不需要再次進行功能測試,可以專一於發生變化的業務的測試,以及終於的集成測試就能夠.

到現在爲止,咱們已經有效攻克了」單project開發模型」中一些問題,對於大部分團隊來講這樣的已經可以了,但是該模型仍然存在一些可以改進的點:每次改動依賴包,就需要又一次編譯生成lib或者aar.比方說小顏同窗接手了一個項目有40多個組件,在最後集成所有組件的時候,小顏同窗發現當中某組件存在問題,爲了定位和改動該組件中的問題,小顏同窗不斷這調試該組件.由於在該模型下,組件不能脫離主project,那麼意味着,每次改動後,小顏同窗都要在漫長的編譯過程當中等待.更糟糕的是,現在離上線僅僅有5小時了,每次編譯10分鐘,爲改這個bug,編譯了20次,恩….什麼也不用幹了,可以提交離職報告了

怎樣解決這樣的每次改動組件都要連同主project一塊兒編譯的問題?如下咱們來看主project多子project開發模型是怎樣解決該問題的.

主project多子project開發模型

該種開發模型在」主project多組件」開發模型的基礎上作了改進,其結構圖例如如下:

這裏寫圖片描寫敘述

不難發現,該種開發模型在結構上和」主project多組件」並沒有不一樣,惟一的差異在於:所有業務組件再也不是mouble而是做爲一個子project,基礎組件可以使moudle,也可以是子project,該子project和主project不一樣:Debug模式下下做爲app,可以單獨的開發,執行,調試;Release模式下做爲Library,被主project所依賴,向主project提供服務.

在該種模型下,當小顏同窗發現某個業務組件存在缺陷,會怎樣作呢?

比方是基礎組件2出現故障,由於在Debug模式下,基礎組件2做爲app可以獨立執行的,所以可以很是easy地對該模塊進行單獨改動,調試.最後改動完後僅僅需要又一次編譯一次整個項目就能夠.

不難發現該種開發模型有效的下降了全編譯的次數,下降編譯耗時的同一時候,方便開發者進行開發調試.

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

到現在,咱們在理論層次上講明瞭採用組件化開發給咱們帶來的便利,空口無憑是沒有說服力的,在如下的一小節中,咱們來談談怎樣組件化在Android中的實施過程.

組件化過程當中遇到的問題

組件劃分

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

子project工做方式切換

在」主project多子project模型」中,咱們提到子project在Debug模式下作爲單獨的Application執行,在Release模式下做爲Library執行,怎樣去動態改動子project的執行模式呢?咱們都知道採用Gradle構建的project中,用apply plugin: 'com.android.application'來標識該爲Application,而apply plugin: 'com.android.library'標誌位Library.所以,咱們可以在編譯的是同經過推斷構建環境中的參數來改動子project的工做方式,在子project的gradle腳本頭部加入如下腳本片斷:

if (isDebug.toBoolean()) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}

除此以外,子project中在不一樣的執行方式下,其AndroidMainifest.xml也是不相同的,需要爲其分別提供本身AndroidManifest.xml文件:在子projectsrc文件夾下(其它位置建立)建立兩個文件夾,用來存放不一樣的AndroidManifest.xml,比方這裏我建立了debug和release文件夾
這裏寫圖片描寫敘述
接下來相同需要在該子project的gradle構建腳本中依據構建方式制定:

android {
    sourceSets {
        main {
            if(isDebug.toBoolean()) {
                manifest.srcFile 'src/debug/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/release/AndroidManifest.xml'
            }
        }
    }
}

組件通訊與組件依賴

在」主project多組件」這樣的理想模型下業務組件是不存在相互通訊和依賴的,但現實倒是相反的,例如如下圖:
這裏寫圖片描寫敘述

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

現在咱們再來看一種更糟糕的狀況:
這裏寫圖片描寫敘述

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

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

解決組件通訊

先來解決業務組件通訊問題.當年看到上面那張複雜的組件通訊圖時,咱們不難想到操做系統引入總線機制來解決設備掛載問題,相同,借用總線的概念咱們在project加入」組件總線」,用於不一樣組件間的通訊,此時結構例如如下:
這裏寫圖片描寫敘述

所有掛載到組件總線上的業務組件,都可以實現雙向通訊.而通訊協議和HTTP通訊協議類似,即基於URL的方式進行.至於實現的方式一種可以基於系統提供的隱式意圖的方式,還有一種則是全然自行實現組件總線.這篇文章不打算在此不作具體說明了.

解決反覆依賴

對於採用aar方式輸出的Library而言,在構建項目時,gradle會爲咱們保留最新版本號的aar,換言之,假設以aar的方式向主project提供提供依賴不會存在反覆依賴的問題.而假設是直接以project形式提供依賴,則在打包過程當中會出現反覆的代碼.解決project反覆依賴問題眼下有兩種作法:1.對於純代碼project的庫或jar包而言,僅僅在終於項目中執行compile,其它狀況採用provider方式;2.在編譯時檢測依賴的包,已經依賴的再也不依賴

資源id衝突

在合併多個組件到主project中時,可能會出現資源引用衝突,
最簡單的方式是經過實現約定資源前綴名(resourcePrefix)來避免,需要在組件的gradle腳本中配置:

andorid{
    ...

    buildTypes{
        ...
    }

    resourcePrefix "moudle_prefix"

}

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

組件上下文(Context)

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


結束語

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

敬請期待第二篇,咱們將在第二篇內介紹怎樣對項目實施組件化.

相關文章
相關標籤/搜索