比較早期的時(shí)候,我們開(kāi)發(fā)APP都是采用單一工程模式,隨著業(yè)務(wù)的發(fā)展黄伊,APP越來(lái)越龐大,開(kāi)發(fā)人員越來(lái)越多派殷,所以必然面臨著將老項(xiàng)目進(jìn)行組件化的過(guò)程还最。
在將老項(xiàng)目進(jìn)行組件化的過(guò)程中墓阀,會(huì)面臨很多的問(wèn)題,以我自己的經(jīng)驗(yàn)為例拓轻,主要有以下點(diǎn):
- 代碼年久失修斯撮,文檔缺失,不敢隨意修改扶叉,否則會(huì)牽一發(fā)而動(dòng)全身勿锅,引起現(xiàn)有正常業(yè)務(wù)的運(yùn)行;
- 進(jìn)行組件化重構(gòu)需要花費(fèi)比較長(zhǎng)的時(shí)間枣氧,業(yè)務(wù)不可能停下來(lái)等著你去重構(gòu)粱甫;
- 組件化重構(gòu)后,需要全量回歸測(cè)試作瞄,測(cè)試比較花費(fèi)時(shí)間茶宵;
相信每個(gè)人都會(huì)碰到這些問(wèn)題,組件化重構(gòu)勢(shì)在必行宗挥,但是老板不可能專(zhuān)門(mén)給你幾個(gè)月乌庶,啥業(yè)務(wù)都不做就讓你進(jìn)行代碼重構(gòu)。那怎么辦呢契耿,我這里講講自己的一些經(jīng)驗(yàn)瞒大,供大家參考。
1. 優(yōu)先集成路由框架
首先搪桂,在老項(xiàng)目中引入路由框架透敌,不管是自己簡(jiǎn)單設(shè)計(jì)的也好,還是采用第三方框架踢械,新開(kāi)發(fā)的功能頁(yè)面跳轉(zhuǎn)一律采用路由酗电,老的頁(yè)面跳轉(zhuǎn)逐步替換。這樣做的目的是盡量減少代碼耦合内列,為后面進(jìn)行模塊拆分打下基礎(chǔ)撵术。
2. 業(yè)務(wù)模塊拆分
一個(gè)老項(xiàng)目必然經(jīng)過(guò)很多人的手,你不一定要對(duì)所有代碼都很熟悉话瞧,但是你必須要基本了解所有的業(yè)務(wù)功能嫩与,在此基礎(chǔ)上對(duì)所有業(yè)務(wù)進(jìn)行初步的模塊劃分。這個(gè)業(yè)務(wù)模塊劃分交排,粒度可以粗一點(diǎn)划滋,原則上一個(gè)業(yè)務(wù)模塊只是實(shí)現(xiàn)某一個(gè)子功能。
以我自己為例埃篓,我會(huì)采用xmind或類(lèi)似工具处坪,將所拆分的業(yè)務(wù)畫(huà)出來(lái),就像一個(gè)公司的組織架構(gòu)一樣:公司由若干個(gè)大的事業(yè)部組成,每個(gè)事業(yè)部包含若干個(gè)二級(jí)部門(mén)稻薇,二級(jí)部門(mén)又有可能包含三級(jí)部門(mén)嫂冻。將你的項(xiàng)目劃分成幾個(gè)大的業(yè)務(wù),每個(gè)大的業(yè)務(wù)再細(xì)化成若干個(gè)小的業(yè)務(wù)塞椎,業(yè)務(wù)層次劃分不必太細(xì)桨仿,一般保持2層即可,否則設(shè)計(jì)的組件太多案狠,實(shí)施起來(lái)會(huì)更加繁瑣服傍。
總之,最后你一定要有一張你的整體業(yè)務(wù)架構(gòu)圖骂铁,如上圖所示吹零,它僅僅是你對(duì)APP所有業(yè)務(wù)的模塊劃分。
3. 嘗試抽取出一個(gè)基礎(chǔ)的業(yè)務(wù)組件
羅馬不是一天造成的拉庵,人不能一口吃成一個(gè)胖子灿椅。同樣,你也不可能一下子將所有的業(yè)務(wù)钞支,都進(jìn)行組件化剝離出來(lái)茫蛹。萬(wàn)事開(kāi)頭難,特別是老項(xiàng)目在進(jìn)行組件化重構(gòu)時(shí)烁挟,往往我們會(huì)有無(wú)從下手的感覺(jué)婴洼。回顧一下上一節(jié)中你整理出來(lái)的業(yè)務(wù)架構(gòu)圖撼嗓,從中找出一個(gè)你覺(jué)得最核心最基礎(chǔ)的業(yè)務(wù)柬采,也就是你覺(jué)得這個(gè)業(yè)務(wù)必須最先進(jìn)行組件化重構(gòu)。通常情況下且警,我會(huì)選擇“注冊(cè)/登錄”這個(gè)業(yè)務(wù)模塊粉捻,在我們的應(yīng)用里,很多業(yè)務(wù)都是需要用戶(hù)登錄的振湾。
首先杀迹,新建一個(gè)工程,不管三七二十一押搪,把老工程里的注冊(cè)、登錄相關(guān)的代碼拷貝過(guò)來(lái)浅碾,包括Activity類(lèi)大州、布局xml文件、圖片文件等垂谢,其他的暫時(shí)不要考慮厦画。這個(gè)時(shí)候,你會(huì)發(fā)現(xiàn)新的工程里,到處都是紅色的警告錯(cuò)誤根暑,要么依賴(lài)的某個(gè)類(lèi)不存在力试,要么依賴(lài)的某個(gè)資源文件不存在,根本無(wú)法編譯運(yùn)行排嫌。不能運(yùn)行就對(duì)了畸裳,顯然這種粗暴的方式行不通,如果你嘗試去解決淳地,你會(huì)發(fā)現(xiàn)類(lèi)似這樣的依賴(lài)路徑:A -> B -> C ->D怖糊,你得把所有依賴(lài)的類(lèi)或資源拷貝到新工程里,這可能會(huì)形成一顆巨大的依賴(lài)樹(shù)颇象,實(shí)施起來(lái)難度太大了伍伤,基本不現(xiàn)實(shí)。
顯然遣钳,想直接把老工程的代碼原樣復(fù)制過(guò)來(lái)扰魂,期望一次性成功,大部分情況下都不會(huì)成功蕴茴。那么我們要怎么做呢劝评,現(xiàn)在又會(huì)有一種無(wú)從下手的感覺(jué)了。
4. 畫(huà)出代碼的依賴(lài)關(guān)系圖
我們把老工程的代碼復(fù)制過(guò)來(lái)之后荐开,發(fā)現(xiàn)依賴(lài)的資源太多了付翁,壓根沒(méi)法編譯運(yùn)行。既然我想把“注冊(cè)晃听、登錄”這個(gè)業(yè)務(wù)模塊做成一個(gè)獨(dú)立的組件百侧,那么這個(gè)業(yè)務(wù)模塊里所依賴(lài)的其他資源,是不是也得是個(gè)獨(dú)立的組件能扒。同樣佣渴,采用xmind畫(huà)出“注冊(cè)、登錄”這個(gè)業(yè)務(wù)所依賴(lài)的其他資源初斑,如下圖所示:
通過(guò)查看新工程里報(bào)錯(cuò)的地方辛润,大概可以總結(jié)出“注冊(cè)、登錄”業(yè)務(wù)需要依賴(lài)上圖所示的這些資源见秤。
5. 抽取出基礎(chǔ)功能組件
當(dāng)我們把“注冊(cè)砂竖、登錄”所有依賴(lài)的資源列舉出來(lái)之后,我們先把這些依賴(lài)的東西鹃答,從老工程中抽取出來(lái)乎澄,做成單獨(dú)的組件。
- 日志記錄
打印或者記錄程序運(yùn)行時(shí)日志测摔。 - 網(wǎng)絡(luò)請(qǐng)求
請(qǐng)求服務(wù)端接口用到的網(wǎng)絡(luò)框架置济,例如OkHttp解恰、Retrofit等,或者是自己封裝的框架浙于。 - 數(shù)據(jù)庫(kù)等數(shù)據(jù)存儲(chǔ)
用戶(hù)登錄后护盈,需要保存登錄信息到本地,采用數(shù)據(jù)庫(kù)或者SharedPreference等存儲(chǔ)羞酗。 - 圖片腐宋、樣式、字符串等資源
UI相關(guān)的各種資源整慎,有些資源是全局通用的脏款,有些是該業(yè)務(wù)里獨(dú)有的,我們只把通用的UI資源放到組件里裤园,因?yàn)檫@些需要共用的撤师。 - 常用的一些工具類(lèi)
例如字符串處理、日期格式化拧揽、dp與px轉(zhuǎn)換等剃盾。 - BaseActivity等Base類(lèi)
BaseActivity是所有Activity都必須繼承的父類(lèi),在這里定義一些Activity通用的行為淤袜,例如友盟統(tǒng)計(jì)埋點(diǎn)等痒谴。
我們先按照這些功能,建立對(duì)應(yīng)的基礎(chǔ)功能組件模塊铡羡,然后將注冊(cè)积蔚、登錄業(yè)務(wù)里需要用到的從老工程移到對(duì)應(yīng)的組件模塊里。剛開(kāi)始的時(shí)候烦周,我們的目標(biāo)是先創(chuàng)建組件尽爆,組件的功能也許很薄弱,代碼也許很凌亂读慎,規(guī)范也沒(méi)有漱贱,但是我們先不管它,先做到能用就行夭委。先有基本的框架幅狮,等架子搭起來(lái)之后,我們?cè)偃ヘS滿(mǎn)血肉株灸。
6. 重新封裝基礎(chǔ)業(yè)務(wù)組件
上一節(jié)中的基礎(chǔ)功能組件封裝好之后崇摄,在“注冊(cè)、登錄”這個(gè)組件工程里慌烧,依賴(lài)需要的基礎(chǔ)組件配猫,然后逐步解決沖突錯(cuò)誤等,直到該工程能夠獨(dú)立運(yùn)行杏死。最后,我們需要花時(shí)間調(diào)整代碼規(guī)范,優(yōu)化代碼結(jié)構(gòu)等淑翼。
7. 新老代碼共存
到現(xiàn)在為止腐巢,我們已經(jīng)將一個(gè)業(yè)務(wù)組件獨(dú)立出來(lái)。接下來(lái)玄括,我們需要將該組件集成到老工程里去冯丙,只需要將注冊(cè)、登錄的跳轉(zhuǎn)入口改一下遭京,就可以使用了胃惜。經(jīng)過(guò)測(cè)試之后,逐步刪除老工程里的舊代碼哪雕,這樣下來(lái)之后船殉,注冊(cè)、登錄使用的是新的組件斯嚎,而其他功能依舊沒(méi)變利虫。
接下來(lái)的時(shí)間里,我們采取開(kāi)發(fā)新功能與重構(gòu)并行的方式堡僻,每周安排一部分人去重構(gòu)糠惫,一部分人依舊在老工程里開(kāi)發(fā),經(jīng)過(guò)一段時(shí)間之后钉疫,逐步將老工程的業(yè)務(wù)全部組件化硼讽,到最后老工程里應(yīng)該幾乎沒(méi)代碼了。但是在這個(gè)期間牲阁,我們的項(xiàng)目工程里可能會(huì)包含很多冗余的代碼固阁、冗余的資源文件等,這也會(huì)導(dǎo)致APP的包大小增大咨油,但這些是不可避免的您炉。
小結(jié)
老項(xiàng)目組件化是一個(gè)漸進(jìn)的過(guò)程,我們必須先選定一個(gè)突破口役电,完成一個(gè)組件之后赚爵,后面其他的業(yè)務(wù)實(shí)施組件化就會(huì)相對(duì)容易多了。我們必須控制好整個(gè)組件化實(shí)施的周期法瑟,嚴(yán)格按照計(jì)劃執(zhí)行冀膝,同時(shí)要把握好新功能開(kāi)發(fā)與重構(gòu)之間的度。
系列文章
Android組件化開(kāi)發(fā)實(shí)踐(一):為什么要進(jìn)行組件化開(kāi)發(fā)霎挟?
Android組件化開(kāi)發(fā)實(shí)踐(二):組件化架構(gòu)設(shè)計(jì)
Android組件化開(kāi)發(fā)實(shí)踐(三):組件開(kāi)發(fā)規(guī)范
Android組件化開(kāi)發(fā)實(shí)踐(四):組件間通信問(wèn)題
Android組件化開(kāi)發(fā)實(shí)踐(五):組件生命周期管理
Android組件化開(kāi)發(fā)實(shí)踐(六):老項(xiàng)目實(shí)施組件化
Android組件化開(kāi)發(fā)實(shí)踐(七):開(kāi)發(fā)常見(jiàn)問(wèn)題及解決方案
Android組件化開(kāi)發(fā)實(shí)踐(八):組件生命周期如何實(shí)現(xiàn)自動(dòng)注冊(cè)管理
Android組件化開(kāi)發(fā)實(shí)踐(九):自定義Gradle插件
Android組件化開(kāi)發(fā)實(shí)踐(十):通過(guò)Gradle插件統(tǒng)一規(guī)范