發(fā)現(xiàn)問(wèn)題
改造公司一個(gè)工程
表面看著是不是還算清爽凰萨?我以為她的結(jié)構(gòu)是這樣子的:
仔細(xì)研究绑警,發(fā)現(xiàn)她的結(jié)構(gòu)竟然是這樣子的:
除了基本的依賴(lài)關(guān)系擂送,還有密密麻麻紅色部分的依賴(lài)關(guān)系回溺,模塊之間的調(diào)用十分嚴(yán)重春贸,這讓后期維護(hù)的人很頭疼混萝,在修改某一模塊功能時(shí)遗遵,可能會(huì)影響多個(gè)模塊。簡(jiǎn)單說(shuō)就是耦合性太高逸嘀。
選擇解決方案
既然發(fā)現(xiàn)车要,目前問(wèn)題是工程耦合性太高,那下一步就是工程解耦崭倘。所以就選擇用路由器這種方式去解耦:
路由器的作用是:一個(gè)消息中轉(zhuǎn)站翼岁。
之前模塊之間直接相互調(diào)用,現(xiàn)在模塊之間通過(guò)路由器達(dá)到通信作用司光,我們只需要將所有模塊依賴(lài)于路由器琅坡,就解除了模塊之間的依賴(lài)關(guān)系。
目前業(yè)內(nèi)有很多優(yōu)秀的路由框架残家,例如阿里的ARouter等等榆俺,確實(shí)很好用,但這些路由框架有些龐大坞淮,很多功能我們可能使用不到茴晋,為了減少工程不必要的代碼,同時(shí)基于路由框架原理也不是很復(fù)雜的情況下回窘,還是讓我們自己實(shí)現(xiàn)一個(gè)超輕量級(jí)的路由框架诺擅,玩耍一下。
超輕量級(jí)路由框架SRouter的實(shí)現(xiàn)
路由器的核心是一個(gè)消息中轉(zhuǎn)站啡直,所以先實(shí)現(xiàn)一個(gè)消息中轉(zhuǎn)處理類(lèi)烁涌,這里起名SRouter.java苍碟。既然是處理轉(zhuǎn)發(fā)消息的,那就需要建立相應(yīng)的消息通道撮执,這里應(yīng)該支持多通道驰怎,可以讓不同種類(lèi)的消息通過(guò)不同種類(lèi)的消息通道來(lái)達(dá)到傳遞作用,我們需要一個(gè)隊(duì)列來(lái)存儲(chǔ)這些不同種類(lèi)的消息通道二打,第一步實(shí)現(xiàn)如下:
這里首先是一個(gè)單例模式县忌,使路由器支持多線程,然后使用HashMap初始化一個(gè)隊(duì)列mActions继效,用來(lái)存儲(chǔ)不同種類(lèi)的消息通道症杏,如上。
消息通道隊(duì)列初始化之后瑞信,就需要實(shí)現(xiàn)往隊(duì)列插入不同消息通道的方法厉颤,這里參數(shù)包括通道名稱(chēng)action和通道本身SAction.java,如上凡简。
然后就是實(shí)現(xiàn)往指定通道發(fā)送消息的方法逼友,如上。
實(shí)現(xiàn)了SRouter.java秤涩,框架就有了基本的路由邏輯控制部分帜乞,其中包括了消息通道的建立和發(fā)送消息到指定消息通道。在SRouter.java中筐眷,看到通道SAction.java的使用黎烈,這里說(shuō)一下這個(gè)通道的定義:
通道使用抽象方式的方式實(shí)現(xiàn),參數(shù)context是上下文匀谣,這個(gè)參數(shù)意義很重要照棋,用Context就可以跟系統(tǒng)的消息系統(tǒng)對(duì)接起來(lái),支持不同場(chǎng)景的消息通信武翎,比如說(shuō)多進(jìn)程等等烈炭,參數(shù)requestData為HashMap類(lèi)型,支持多種消息類(lèi)型宝恶。
接下來(lái)符隙,就要具體定義消息發(fā)送的載體類(lèi),這里起名SRouterRequest.java卑惜。
可以看到膏执,消息發(fā)送載體類(lèi)包含兩個(gè)部分,action和data露久,其中action就是通道名稱(chēng)更米,通過(guò)action識(shí)別使用哪個(gè)消息通道,data就是通道所要傳遞的消息體毫痕,這里重點(diǎn)說(shuō)一下data征峦,目前定義為HashMap<String,Object>迟几,盡量支持多種消息類(lèi)型。
到此栏笆,基本功能已經(jīng)有了类腮,但為了讓系統(tǒng)成為一個(gè)閉環(huán),我們要在消息發(fā)送之后蛉加,給發(fā)送者一個(gè)反饋蚜枢,所以這里就需要實(shí)現(xiàn)消息反饋的載體類(lèi)SRouterResponse.java。
消息反饋的載體類(lèi)中针饥,包含了statusCode(反饋狀態(tài)碼)厂抽,statusDesc(反饋狀態(tài)提示語(yǔ)),body(反饋攜帶的內(nèi)容)丁眼。
好了筷凤,到此,超輕量路由框架已經(jīng)實(shí)現(xiàn)苞七,下來(lái)就是趕緊使用一下藐守,體驗(yàn)一把~
使用
我寫(xiě)了一個(gè)demo工程(https://github.com/sarlmoclen/SRouterDemo),用這個(gè)講解下如何使用蹂风。
第一步:就是初始化通道卢厂,通道的建立由自己實(shí)際情況決定,本工程中硫眨,AppMain足淆,AppChildOneSameProcess,AppChildTwoSameProcess礁阁,AppChildThreeDifferentProcess有四個(gè)測(cè)試module,前三個(gè)是在同一進(jìn)程族奢,最后一個(gè)在另外一個(gè)進(jìn)程(測(cè)試多進(jìn)程下路由框架的使用)姥闭。所以這里需要四個(gè)通道,每個(gè)module對(duì)應(yīng)一個(gè)通道越走,用來(lái)傳遞信息棚品。
確認(rèn)了通道數(shù)量,那我們就可以初始化通道了:
通道的建立要盡早廊敌,所以放在Application中铜跑,我簡(jiǎn)單封裝了一個(gè)SApplication.java。這里有個(gè)小的重點(diǎn)需要講一下骡澈,在多進(jìn)程情況下锅纺,Application會(huì)在每個(gè)進(jìn)程下執(zhí)行一遍,這樣的話(huà)肋殴,在本demo中有兩個(gè)進(jìn)程囤锉,所以我們的通道隊(duì)列就會(huì)在每個(gè)進(jìn)程有一個(gè)復(fù)制(進(jìn)程有自己的存儲(chǔ)空間)坦弟,我們就利用這一點(diǎn),讓跨進(jìn)程的情況下官地,也可以使通道被找到酿傍。
第二步:實(shí)現(xiàn)通道,在上一步初始化中驱入,可以看到OneAction赤炒,TwoAction,ThreeAction亏较,MainAction可霎,這些都是每個(gè)module通道的實(shí)現(xiàn),這里以AppMain的通道實(shí)現(xiàn)為例子簡(jiǎn)單說(shuō)明一下:
可以看到requestData是通道收到的消息宴杀,然后我們利用context去傳遞信息癣朗,上面講過(guò)這個(gè)context很重要,這里說(shuō)明一下旺罢,在我們開(kāi)發(fā)app時(shí)候旷余,使用的就是常說(shuō)的四大組件(Activity,Service扁达,ContentProvider正卧,BroadcastReceiver),context完美支持了四大組件的通信跪解,當(dāng)然也支持跨進(jìn)程炉旷。
第三步:發(fā)送消息
使用SRouter.java提供的發(fā)送消息的方法,給指定通道叉讥,發(fā)送需要的消息窘行。
方便使用
好了!到此我們就可以隨便愉快的玩耍了图仓。
只需給工程根部依賴(lài)路由框架罐盔,把之前模塊間的鏈接關(guān)系切換到路由器上,工程就會(huì)恢復(fù)清晰的結(jié)構(gòu)救崔。這個(gè)小路由已經(jīng)測(cè)試使用了近一年時(shí)間惶看,運(yùn)行良好,SRouter已經(jīng)被我上傳到了maven倉(cāng)庫(kù)六孵,方面使用:
compile 'com.sarlmoclen.router:SRouter:0.0.1'
github項(xiàng)目地址:https://github.com/sarlmoclen/SRouterDemo