<p><img src="http://upload-images.jianshu.io/upload_images/11462765-6b9f04f8eefade48" /></p><section><span style="letter-spacing: 0px;">之前寫(xiě)過(guò)一篇關(guān)于Android組件化的文章,</span>
</section><section class="output_wrapper"><p>《Android組件化框架設(shè)計(jì)與實(shí)踐》</p>器钟,之前沒(méi)看過(guò)的小伙伴可以先點(diǎn)擊閱讀。那篇文章是從實(shí)戰(zhàn)中進(jìn)行總結(jié)得來(lái)妙蔗,是公司的一個(gè)真實(shí)項(xiàng)目進(jìn)行組件化架構(gòu)改造傲霸,粒度會(huì)分的更粗些,是對(duì)整體架構(gòu)實(shí)踐進(jìn)行相應(yīng)的總結(jié)灭必,里面說(shuō)了要打造一個(gè)組件化框架的話狞谱,需要從以下7個(gè)方面入手:<p></p><ul class=" list-paddingleft-2"><li><p><span>代碼解耦。如何將一個(gè)龐大的工程分成有機(jī)的整體禁漓?</span></p></li><li><p><span>組件單獨(dú)運(yùn)行跟衅。因?yàn)槊總€(gè)組件都是高度內(nèi)聚的,是一個(gè)完整的整體播歼,如何讓其單獨(dú)運(yùn)行和調(diào)試伶跷?</span></p></li><li><p><span>組件間通信。由于每個(gè)組件具體實(shí)現(xiàn)細(xì)節(jié)都互相不了解秘狞,但每個(gè)組件都需要給其他調(diào)用方提供服務(wù)叭莫,那么主項(xiàng)目與組件、組件與組件之間如何通信就變成關(guān)鍵烁试?</span></p></li><li><p><span>UI 跳轉(zhuǎn)雇初。UI 跳轉(zhuǎn)指的是特殊的數(shù)據(jù)傳遞,跟組件間通信區(qū)別有什么不同减响?</span></p></li><li><p><span>組件生命周期靖诗。這里的生命周期指的是組件在應(yīng)用中存在的時(shí)間,組件是否可以做到按需支示、動(dòng)態(tài)使用刊橘、因此就會(huì)涉及到組件加載、卸載等管理問(wèn)題颂鸿。</span></p></li><li><p><span>集成調(diào)試促绵。在開(kāi)發(fā)階段如何做到按需編譯組件?一次調(diào)試中可能有一兩個(gè)組件參與集成,這樣編譯時(shí)間就會(huì)大大降低败晴,提高開(kāi)發(fā)效率浓冒。</span></p></li><li><p><span>代碼隔離。組件之間的交互如果還是直接引用的話位衩,那么組件之間根本沒(méi)有做到解耦裆蒸,如何從根本上避免組件之間的直接引用,也就是如何從根本上杜絕耦合的產(chǎn)生糖驴?</span></p></li></ul><p>今天則會(huì)從更小細(xì)粒度入手僚祷,主要講講在組件化架構(gòu)下組件與組件之間通信機(jī)制是如何、包括所謂的UI跳轉(zhuǎn)贮缕,其實(shí)也是組件化通信辙谜,只不過(guò)它稍微特殊點(diǎn),單獨(dú)抽取出來(lái)而已感昼。學(xué)習(xí)知識(shí)的過(guò)程很常見(jiàn)的一個(gè)思路就是從整體概況入手装哆,首先對(duì)整體有個(gè)粗略的印象,然后再深入細(xì)節(jié)定嗓,抽絲剝繭般去挖掘其中的內(nèi)在原理蜕琴,一個(gè)點(diǎn)一個(gè)不斷去突破,這樣就能建立起自己整個(gè)知識(shí)樹(shù)宵溅,所以今天我們就從通信機(jī)制這個(gè)點(diǎn)入手凌简,看看其中內(nèi)在玄機(jī)有哪些。</p><h4><span>思維導(dǎo)圖</span></h4><p>同樣恃逻,在每寫(xiě)一篇文章之前雏搂,放個(gè)思維導(dǎo)圖,這樣做的好處對(duì)于想寫(xiě)的內(nèi)容有很好的梳理寇损,邏輯和結(jié)構(gòu)上顯得清晰點(diǎn)凸郑。</p><figure><img class="" data-ratio="0.5280172413793104" src="http://upload-images.jianshu.io/upload_images/11462765-3f164cd035457494.png" data-type="png" data-w="1856" title="思維導(dǎo)圖"><figcaption>思維導(dǎo)圖</figcaption></figure><h4><span>主流方式</span></h4><p>總所周知,Android提供了很多不同的信息的傳遞方式矛市,比如在四大組件中本地廣播芙沥、進(jìn)程間的AIDL颅痊、匿名間的內(nèi)存共享钙姊、Intent Bundle傳遞等等辛萍,那么在這么多傳遞方式想暗,哪種類(lèi)型是比較適合組件與組件直接的傳遞呢。</p><ul class=" list-paddingleft-2"><li><p><span>本地廣播杭措,也就是LoacalBroadcastRecevier。更多是用在同一個(gè)應(yīng)用內(nèi)的不同系統(tǒng)規(guī)定的組件進(jìn)行通信,好處在于:發(fā)送的廣播只會(huì)在自己的APP內(nèi)傳播午阵,不會(huì)泄漏給其他的APP,其他APP無(wú)法向自己的APP發(fā)送廣播,不用被其他APP干擾底桂。本地廣播好比對(duì)講通信植袍,成本低,效率高籽懦,但有個(gè)缺點(diǎn)就是兩者通信機(jī)制全部委托與系統(tǒng)負(fù)責(zé)于个,我們無(wú)法干預(yù)傳輸途中的任何步驟,不可控制暮顺,一般在組件化通信過(guò)程中采用比例不高厅篓。</span></p></li><li><p><span>進(jìn)程間的AIDL。這個(gè)粒度在于進(jìn)程捶码,而我們組件化通信過(guò)程往往是在線程中羽氮,況且AIDL通信也是屬于系統(tǒng)級(jí)通信,底層以Binder機(jī)制惫恼,雖說(shuō)Android提供模板供我們實(shí)現(xiàn)档押,但往往使用者不好理解,交互比較復(fù)雜祈纯,往往也不適用應(yīng)用于組件化通信過(guò)程中令宿。</span></p></li><li><p><span>匿名的內(nèi)存共享。比如用Sharedpreferences腕窥,在處于多線程場(chǎng)景下粒没,往往會(huì)線程不安全,這種更多是存儲(chǔ)一一些變化很少的信息油昂,比如說(shuō)組件里的配置信息等等革娄。</span></p></li><li><p><span>Intent Bundle傳遞。包括顯性和隱性傳遞冕碟,顯性傳遞需要明確包名路徑拦惋,組件與組件往往是需要互相依賴(lài),這背離組件化中SOP(關(guān)注點(diǎn)分離原則)安寺,如果走隱性的話厕妖,不僅包名路徑不能重復(fù),需要定義一套規(guī)則挑庶,只有一個(gè)包名路徑出錯(cuò)言秸,排查起來(lái)也稍顯麻煩,這個(gè)方式往往在組件間內(nèi)部傳遞會(huì)比較合適迎捺,組件外與其他組件打交道則使用場(chǎng)景不多举畸。</span></p></li></ul><p>說(shuō)了這么多,那組件化通信什么機(jī)制比較適合呢凳枝?既然組件層中的模塊是相互獨(dú)立的抄沮,它們之間并不存在任何依賴(lài)跋核。沒(méi)有依賴(lài)就無(wú)法產(chǎn)生關(guān)系,沒(méi)有關(guān)系叛买,就無(wú)法傳遞消息砂代,那要如何才能完成這種交流?</p><p>目前主流做法之一就是引入第三者率挣,比如圖中的Base Module刻伊。</p><figure><img class="" data-ratio="0.5897058823529412" src="http://upload-images.jianshu.io/upload_images/11462765-9eed735e6676e6de.png" data-type="png" data-w="680" title="基礎(chǔ)組件化架構(gòu)"><figcaption>基礎(chǔ)組件化架構(gòu)</figcaption></figure><p>組件層的模塊都依賴(lài)于基礎(chǔ)層,從而產(chǎn)生第三者聯(lián)系椒功,這種第三者聯(lián)系最終會(huì)編譯在APP Module中捶箱,那時(shí)將不會(huì)有這種隔閡,那么其中的Base Module就是跨越組件化層級(jí)的關(guān)鍵蛾茉,也是模塊間信息交流的基礎(chǔ)讼呢。比較有代表性的組件化開(kāi)源框架有得到DDComponentForAndroid、阿里Arouter谦炬、聚美Router 等等悦屏。</p><p>除了這種以通過(guò)引入第三者方式,還有一種解決方式是以事件總線方式键思,但這種方式目前開(kāi)源的框架中使用比例不高础爬,如圖:</p><figure><img class="" data-ratio="0.3681462140992167" src="http://upload-images.jianshu.io/upload_images/11462765-86e5f08c5e89e373.png" data-type="png" data-w="766" title="事件總線"><figcaption>事件總線</figcaption></figure><p>事件總線通過(guò)記錄對(duì)象,使用監(jiān)聽(tīng)者模式來(lái)通知對(duì)象各種事件吼鳞,比如在現(xiàn)實(shí)生活中看蚜,我們要去找房子,一般都去看小區(qū)的公告欄赔桌,因?yàn)槟沁厱?huì)經(jīng)常發(fā)布一些出租信息供炎,我們?nèi)ゲ榭吹倪^(guò)程中就形成了訂閱的關(guān)系,只不過(guò)這種是被動(dòng)去訂閱疾党,因?yàn)橹挥凶约盒枰曳孔恿瞬湃タ匆艚耄綍r(shí)一般不會(huì)去看。小區(qū)中的公告欄可以想象成一個(gè)事件總線發(fā)布點(diǎn)雪位,監(jiān)聽(tīng)者則是哪些想要找房子的人竭钝,當(dāng)有房東在公告欄上貼上出租房信息時(shí),如果公告欄有訂閱信息功能雹洗,比如引入門(mén)衛(wèi)保安香罐,已經(jīng)把之前來(lái)這個(gè)公告欄要查看的找房子人一一進(jìn)行電話登記,那么一旦有新出租消息產(chǎn)生时肿,則門(mén)衛(wèi)會(huì)把這條消息一一進(jìn)行短信群發(fā)庇茫,那么找房子人則會(huì)收到這條消息進(jìn)行后續(xù)的操作,是馬上過(guò)來(lái)看螃成,還是延遲過(guò)來(lái)旦签,則根據(jù)自己的實(shí)際情況進(jìn)行處理啥容。在目前開(kāi)源庫(kù)中,有EventBus顷霹、RxBus就是采用這種發(fā)布/訂閱模式,優(yōu)點(diǎn)是簡(jiǎn)化了Android組件之間的通信方式击吱,實(shí)現(xiàn)解耦淋淀,讓業(yè)務(wù)代碼更加簡(jiǎn)潔,可以動(dòng)態(tài)設(shè)置事件處理線程和優(yōu)先級(jí)覆醇,缺點(diǎn)則是每個(gè)事件需要維護(hù)一個(gè)事件類(lèi)朵纷,造成事件類(lèi)太多,無(wú)形中加大了維護(hù)成本永脓。那么在組件化開(kāi)源框架中有ModuleBus袍辞、CC 等等。</p><p>這兩者模式更詳細(xì)的對(duì)比常摧,可以查看這篇文章多個(gè)維度對(duì)比一些有代表性的開(kāi)源android組件化開(kāi)發(fā)方案</p><h4><span>實(shí)現(xiàn)方案</span></h4><p>事件總線搅吁,又可以叫做組件總線,路由+接口落午,則相對(duì)好理解點(diǎn)谎懦,今天從閱讀它們框架源碼,我們來(lái)對(duì)比這兩種實(shí)現(xiàn)方案的不同之處溃斋。</p><h6><span>組件總線</span></h6><p>這邊選取的是ModuleBus框架界拦,這個(gè)方案特別之處在于其借鑒了EventBus的思想,組件的注冊(cè)/注銷(xiāo)和組件調(diào)用的事件發(fā)送都跟EventBus類(lèi)似梗劫,能夠傳遞一些基礎(chǔ)類(lèi)型的數(shù)據(jù)享甸,而并不需要在Base Moudel中添加額外的類(lèi)。所以不會(huì)影響B(tài)ase模塊的架構(gòu)梳侨,但是無(wú)法動(dòng)態(tài)移除信息接收端的代碼蛉威,而自定義的事件信息類(lèi)型還是需要添加到Base Module中才能讓其他功能模塊索引。</p><p>其中的核心代碼是在與 <strong>ModuleBus</strong> 類(lèi)猫妙,其內(nèi)部維護(hù)了兩個(gè)ArrayMap鍵對(duì)值列表瓷翻,如下:</p><pre><code class="java language-java hljs"><span class="hljs-comment">/
??????Object?methodClass
??????String?methodName;
??????MethodInfo?method?info
?????/</span>
????<span class="hljs-keyword">private</span>?<span class="hljs-keyword">static</span>?ArrayMap<Object,ArrayMap<String,MethodInfo>>?moduleEventMethods?=?<span class="hljs-keyword">new</span>?ArrayMap<>();
????<span class="hljs-comment">/
??????Class?IBaseClient.class
??????String?methodName
??????Object?methodClass
?????/</span>
????<span class="hljs-keyword">private</span>?<span class="hljs-keyword">static</span>?ArrayMap<Class<?>,ArrayMap<String,ArrayList<Object>>>?moduleMethodClient?=?<span class="hljs-keyword">new</span>?ArrayMap<>();
</code></pre><p>在使用方法上割坠,在onCreate()和onDestroy()中需要注冊(cè)和解綁齐帚,比如</p><pre><code class="java language-java hljs">ModuleBus.getInstance().register(<span class="hljs-keyword">this</span>);
ModuleBus.getInstance().unregister(<span class="hljs-keyword">this</span>);
</code></pre><p>最終使用類(lèi)似EventBus 中 post 方法一樣,進(jìn)行兩個(gè)組件間的通信彼哼。這個(gè)框架的封裝的post 方法如下</p><pre><code class="java language-java hljs"><span class="hljs-function"><span class="hljs-keyword">public</span>?<span class="hljs-keyword">void</span>?<span class="hljs-title">post</span><span class="hljs-params">(Class<?>?clientClass,String?methodName,Object...args)</span></span>{
????????<span class="hljs-keyword">if</span>(clientClass?==?<span class="hljs-keyword">null</span>?||?methodName?==?<span class="hljs-keyword">null</span>?||methodName.length()?==?<span class="hljs-number">0</span>)?<span class="hljs-keyword">return</span>;
????????ArrayList<Object>?clientList?=?getClient(clientClass,methodName);
????????<span class="hljs-keyword">if</span>(clientList?==?<span class="hljs-keyword">null</span>)?<span class="hljs-keyword">return</span>;
????????<span class="hljs-keyword">try</span>{
????????????<span class="hljs-keyword">for</span>(Object?c:?clientList){
????????????????<span class="hljs-keyword">try</span>{
????????????????????ArrayMap<String,MethodInfo>?methods?=?moduleEventMethods.get(c);
????????????????????Method?method?=?methods.get(methodName).m;
????????????????????<span class="hljs-keyword">if</span>(method?==?<span class="hljs-keyword">null</span>){
????????????????????????Log.e(TAG,<span class="hljs-string">"cannot?find?client?method"</span>+methodName?+<span class="hljs-string">"for?args["</span>+args.length+<span class="hljs-string">"]"</span>?+?Arrays.toString(args));
????????????????????????<span class="hljs-keyword">return</span>;
????????????????????}<span class="hljs-keyword">else</span>?<span class="hljs-keyword">if</span>(method.getParameterTypes()?==?<span class="hljs-keyword">null</span>){
????????????????????????Log.e(TAG,<span class="hljs-string">"cannot?find?client?method?param:"</span>+method.getParameterTypes()?+<span class="hljs-string">"for?args["</span>+args.length+<span class="hljs-string">"]"</span>?+?Arrays.toString(args));
????????????????????????<span class="hljs-keyword">return</span>;
????????????????????}<span class="hljs-keyword">else</span>?<span class="hljs-keyword">if</span>(method.getParameterTypes().length?!=?args.length){
????????????????????????Log.e(TAG,<span class="hljs-string">"method?"</span>+methodName?+<span class="hljs-string">"?param?number?not?matched:method("</span>+method.getParameterTypes().length+<span class="hljs-string">"),?args("</span>?+?args.length+<span class="hljs-string">")"</span>);
????????????????????????<span class="hljs-keyword">return</span>;
????????????????????}
????????????????????method.invoke(c,args);
????????????????}<span class="hljs-keyword">catch</span>?(Throwable?e){
????????????????????Log.e(TAG,<span class="hljs-string">"Notifiy?client?method?invoke?error."</span>,e);
????????????????}
????????????}
????????}<span class="hljs-keyword">catch</span>?(Throwable?e){
????????????Log.e(TAG,<span class="hljs-string">"Notify?client?error"</span>,e);
????????}
????}
</code></pre><p>可以看到对妄,它是通過(guò)遍歷之前內(nèi)部的ArrayMap,把注冊(cè)在里面的方法找出敢朱,根據(jù)傳入的參數(shù)進(jìn)行匹配剪菱,使用反射調(diào)用摩瞎。</p><h6><span>接口+路由</span></h6><p>接口+路由實(shí)現(xiàn)方式則相對(duì)容易理解點(diǎn),我之前實(shí)踐的一個(gè)項(xiàng)目就是通過(guò)這種方式實(shí)現(xiàn)的孝常。具體地址如下:DemoComponent實(shí)現(xiàn)思路是專(zhuān)門(mén)抽取一個(gè)LibModule作為路由服務(wù)旗们,每個(gè)組件聲明自己提供的服務(wù) Service API,這些 Service 都是一些接口构灸,組件負(fù)責(zé)將這些 Service 實(shí)現(xiàn)并注冊(cè)到一個(gè)統(tǒng)一的路由 Router 中去上渴,如果要使用某個(gè)組件的功能,只需要向Router 請(qǐng)求這個(gè) Service 的實(shí)現(xiàn)喜颁,具體的實(shí)現(xiàn)細(xì)節(jié)我們?nèi)徊魂P(guān)心稠氮,只要能返回我們需要的結(jié)果就可以了。</p><p>比如定義兩個(gè)路由地址半开,一個(gè)登陸組件隔披,一個(gè)設(shè)置組件,核心代碼:</p><pre><code class="java language-java hljs"><span class="hljs-keyword">public</span>?<span class="hljs-class"><span class="hljs-keyword">class</span>?<span class="hljs-title">RouterPath</span>?</span>{
????<span class="hljs-comment">//注意路由的命名寂拆,路徑第一個(gè)開(kāi)頭需要不一致奢米,保證唯一性</span>
????<span class="hljs-comment">//Login?Service</span>
????<span class="hljs-keyword">public</span>?<span class="hljs-keyword">static</span>?<span class="hljs-keyword">final</span>?String?ROUTER_PATH_TO_LOGIN_SERVICE?=?<span class="hljs-string">"/login/service"</span>;
????<span class="hljs-comment">//Setting?Service</span>
????<span class="hljs-keyword">public</span>?<span class="hljs-keyword">static</span>?<span class="hljs-keyword">final</span>?String?ROUTER_PATH_TO_SETTING_SERVICE?=?<span class="hljs-string">"/setting/service"</span>;
}
</code></pre><p>那么就相應(yīng)著就有兩個(gè)接口API,如下:</p><pre><code class="java language-java hljs"><span class="hljs-keyword">public</span>?<span class="hljs-class"><span class="hljs-keyword">interface</span>?<span class="hljs-title">ILoginProvider</span>?<span class="hljs-keyword">extends</span>?<span class="hljs-title">IProvider</span>?</span>{
????<span class="hljs-function"><span class="hljs-keyword">void</span>?<span class="hljs-title">goToLogin</span><span class="hljs-params">(Activity?activity)</span></span>;
}
<span class="hljs-keyword">public</span>?<span class="hljs-class"><span class="hljs-keyword">interface</span>?<span class="hljs-title">ISettingProvider</span>?<span class="hljs-keyword">extends</span>?<span class="hljs-title">IProvider</span>?</span>{
????<span class="hljs-function"><span class="hljs-keyword">void</span>?<span class="hljs-title">goToSetting</span><span class="hljs-params">(Activity?activity)</span></span>;
}
</code></pre><p>這兩個(gè)接口API對(duì)應(yīng)著是向外暴露這兩個(gè)組件的能提供的通信能力漓库,然后每個(gè)組件對(duì)接口進(jìn)行實(shí)現(xiàn)恃慧,如下:</p><pre><code class="java language-java hljs"><span class="hljs-meta">@Route</span>(path?=?RouterPath.ROUTER_PATH_TO_LOGIN_SERVICE,?name?=?<span class="hljs-string">"登陸頁(yè)面"</span>)
<span class="hljs-keyword">public</span>?<span class="hljs-class"><span class="hljs-keyword">class</span>?<span class="hljs-title">LoginService</span>?<span class="hljs-keyword">implements</span>?<span class="hljs-title">ILoginProvider</span>?</span>{
????<span class="hljs-meta">@Override</span>
????<span class="hljs-function"><span class="hljs-keyword">public</span>?<span class="hljs-keyword">void</span>?<span class="hljs-title">init</span><span class="hljs-params">(Context?context)</span>?</span>{}
????<span class="hljs-meta">@Override</span>
????<span class="hljs-function"><span class="hljs-keyword">public</span>?<span class="hljs-keyword">void</span>?<span class="hljs-title">goToLogin</span><span class="hljs-params">(Activity?activity)</span>?</span>{
????????Intent?loginIntent?=?<span class="hljs-keyword">new</span>?Intent(activity,?LoginActivity.class);
????????activity.startActivity(loginIntent);
????}
}
</code></pre><p>這其中使用的到了阿里的ARouter頁(yè)面跳轉(zhuǎn)方式,內(nèi)部本質(zhì)也是接口+實(shí)現(xiàn)方式進(jìn)行組件間通信渺蒿。</p><p>調(diào)用則很簡(jiǎn)單了痢士,如下:</p><pre><code class="java language-java hljs">?ILoginProvider?loginService?=?(ILoginProvider)?ARouter.getInstance().build(RouterPath.ROUTER_PATH_TO_LOGIN_SERVICE).navigation();
<span class="hljs-keyword">if</span>(loginService?!=?<span class="hljs-keyword">null</span>){
????loginService.goToLogin(MainActivity.<span class="hljs-keyword">this</span>);
}
</code></pre><p>還有一個(gè)組件化框架,就是ModularizationArchitecture 茂装,它本質(zhì)實(shí)現(xiàn)方式也是接口+實(shí)現(xiàn)怠蹂,但是封裝形式稍微不一樣點(diǎn),它是每個(gè)功能模塊中需要使用注解建立Action事件少态,每個(gè)Action完成一個(gè)事件動(dòng)作城侧。invoke只是方法名為反射,并未用到反射彼妻,而是使用接口方式調(diào)用嫌佑,參數(shù)是通過(guò)HashMap<string,string>傳遞的,無(wú)法傳遞對(duì)象侨歉。具體詳解可以看這篇文章 Android架構(gòu)思考(模塊化屋摇、多進(jìn)程)。</string,string></p><h4><span>頁(yè)面跳轉(zhuǎn)</span></h4><p>頁(yè)面跳轉(zhuǎn)也算是一種組件間的通信幽邓,只不過(guò)它相對(duì)粒度更細(xì)化點(diǎn)炮温,之前我們描述的組件間通信粒度會(huì)更抽象點(diǎn),頁(yè)面跳轉(zhuǎn)則是定位到某個(gè)組件的某個(gè)頁(yè)面牵舵,可能是某個(gè)Activity柒啤,或者某個(gè)Fragment倦挂,要跳轉(zhuǎn)到另外一個(gè)組件的Activity或Fragment,是這兩者之間的通信担巩。甚至在一般沒(méi)有進(jìn)行組件化架構(gòu)的工程項(xiàng)目中方援,往往也會(huì)封裝頁(yè)面之間的跳轉(zhuǎn)代碼類(lèi),往往也會(huì)有路由中心的概念涛癌。不過(guò)一般 UI 跳轉(zhuǎn)基本都會(huì)單獨(dú)處理肯骇,一般通過(guò)短鏈的方式來(lái)跳轉(zhuǎn)到具體的 Activity。每個(gè)組件可以注冊(cè)自己所能處理的短鏈的 Scheme 和 Host祖很,并定義傳輸數(shù)據(jù)的格式,然后注冊(cè)到統(tǒng)一的 UIRouter 中漾脂,UIRouter 通過(guò) Scheme 和 Host 的匹配關(guān)系負(fù)責(zé)分發(fā)路由假颇。但目前比較主流的做法是通過(guò)在每個(gè) Activity 上添加注解,然后通過(guò) APT 形成具體的邏輯代碼骨稿。</p><p>下面簡(jiǎn)單介紹目前比較主流的兩個(gè)框架核心實(shí)現(xiàn)思路:</p><h5><span>ARouter</span></h5><p>ARouter 核心實(shí)現(xiàn)思路是笨鸡,我們?cè)诖a里加入的@Route注解,會(huì)在編譯時(shí)期通過(guò)apt生成一些存儲(chǔ)path和activityClass映射關(guān)系的類(lèi)文件坦冠,然后app進(jìn)程啟動(dòng)的時(shí)候會(huì)拿到這些類(lèi)文件形耗,把保存這些映射關(guān)系的數(shù)據(jù)讀到內(nèi)存里(保存在map里),然后在進(jìn)行路由跳轉(zhuǎn)的時(shí)候辙浑,通過(guò)build()方法傳入要到達(dá)頁(yè)面的路由地址激涤,ARouter會(huì)通過(guò)它自己存儲(chǔ)的路由表找到路由地址對(duì)應(yīng)的Activity.class(activity.class = map.get(path)),然后new Intent()判呕,當(dāng)調(diào)用ARouter的withString()方法它的內(nèi)部會(huì)調(diào)用intent.putExtra(String name, String value)倦踢,調(diào)用navigation()方法,它的內(nèi)部會(huì)調(diào)用startActivity(intent)進(jìn)行跳轉(zhuǎn)侠草,這樣便可以實(shí)現(xiàn)兩個(gè)相互沒(méi)有依賴(lài)的module順利的啟動(dòng)對(duì)方的Activity了辱挥。</p><h5><span>ActivityRouter</span></h5><p>ActivityRouter 核心實(shí)現(xiàn)思路是,它是通過(guò)路由 + 靜態(tài)方法來(lái)實(shí)現(xiàn)边涕,在靜態(tài)方法上加注解來(lái)暴露服務(wù)晤碘,但不支持返回值,且參數(shù)固定位(context, bundle)功蜓,基于apt技術(shù)园爷,通過(guò)注解方式來(lái)實(shí)現(xiàn)URL打開(kāi)Activity功能,并支持在WebView和外部瀏覽器使用霞赫,支持多級(jí)Activity跳轉(zhuǎn)腮介,支持Bundle、Uri參數(shù)注入并轉(zhuǎn)換參數(shù)類(lèi)型端衰。它實(shí)現(xiàn)相對(duì)簡(jiǎn)單點(diǎn)叠洗,也是比較早期比較流行的做法甘改,不過(guò)學(xué)習(xí)它也是很有參考意義的。</p><h4><span>小結(jié)</span></h4><p>總的來(lái)說(shuō)灭抑,組件間的通信機(jī)制在組件化編程和組件化架構(gòu)中是很重要的一個(gè)環(huán)節(jié)十艾,可能在每個(gè)組件獨(dú)自開(kāi)發(fā)階段,不需要與其他組件進(jìn)行通信腾节,只需要在內(nèi)部通信即可忘嫉,當(dāng)處于組件集成階段,那就需要大量組件進(jìn)行互相通信案腺,體現(xiàn)在每個(gè)業(yè)務(wù)互相協(xié)作庆冕,如果組件間設(shè)計(jì)的不好,打開(kāi)一個(gè)頁(yè)面或調(diào)用一個(gè)方法劈榨,想當(dāng)耗時(shí)或響應(yīng)慢访递,那么體現(xiàn)的則是這個(gè)APP使用比較卡頓,僅僅打開(kāi)一個(gè)頁(yè)面就是需要好幾秒才能打開(kāi)同辣,則嚴(yán)重影響使用者的體驗(yàn)了拷姿,甚至一些大型APP,可能組件分化更小旱函,種類(lèi)更多响巢,那么組件間的通信則至關(guān)重要了。所以棒妨,要打造一個(gè)良好的組件化框架踪古,如何設(shè)計(jì)一個(gè)更適合自己本身的業(yè)務(wù)類(lèi)型的通信機(jī)制,就需要多多進(jìn)行思考了券腔。</p></section><p>
</p><p>
</p><p style="-webkit-tap-highlight-color: transparent; box-sizing: border-box; margin-top: 16px; margin-bottom: 16px; color: rgb(34, 34, 34); font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif; font-size: 16px;">-----點(diǎn)擊上方關(guān)注持續(xù)收聽(tīng)面試干貨</p><div class="pgc-img" style="-webkit-tap-highlight-color: transparent; box-sizing: border-box; color: rgb(34, 34, 34); font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif; font-size: 16px;"><img src="http://upload-images.jianshu.io/upload_images/11462765-68258e90f4ccc5cb" img_width="411" img_height="150" alt="人工智能竟然會(huì)讓你變得更窮 最遲25年內(nèi)應(yīng)驗(yàn)" inline="0" style="-webkit-tap-highlight-color: transparent; box-sizing: border-box; border-style: none; margin-top: 10px; margin-bottom: 10px;"><p class="pgc-img-caption" style="-webkit-tap-highlight-color: transparent; box-sizing: border-box; text-align: center; font-size: 12px; color: rgb(119, 119, 119); line-height: 16px;"></p></div><p class="ql-align-center" style="-webkit-tap-highlight-color: transparent; box-sizing: border-box; margin-top: 16px; margin-bottom: 16px; color: rgb(34, 34, 34); font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif; font-size: 16px;">私信 “666” 索要Android高級(jí)視頻(Flutter進(jìn)階灾炭,插件化,熱修復(fù)技術(shù))</p>
我所理解的Android組件化之通信機(jī)制
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
- 文/潘曉璐 我一進(jìn)店門(mén)剖笙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)卵洗,“玉大人,你說(shuō)我怎么就攤上這事」澹” “怎么了十绑?”我有些...
- 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)酷勺。 經(jīng)常有香客問(wèn)我本橙,道長(zhǎng),這世上最難降的妖魔是什么脆诉? 我笑而不...
- 正文 為了忘掉前任甚亭,我火速辦了婚禮,結(jié)果婚禮上击胜,老公的妹妹穿的比我還像新娘亏狰。我一直安慰自己,他們只是感情好偶摔,可當(dāng)我...
- 文/花漫 我一把揭開(kāi)白布骚揍。 她就那樣靜靜地躺著,像睡著了一般啰挪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上嘲叔,一...
- 那天亡呵,我揣著相機(jī)與錄音,去河邊找鬼硫戈。 笑死锰什,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的丁逝。 我是一名探鬼主播汁胆,決...
- 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼霜幼!你這毒婦竟也來(lái)了嫩码?” 一聲冷哼從身側(cè)響起,我...
- 序言:老撾萬(wàn)榮一對(duì)情侶失蹤罪既,失蹤者是張志新(化名)和其女友劉穎铸题,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體琢感,經(jīng)...
- 正文 獨(dú)居荒郊野嶺守林人離奇死亡丢间,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
- 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了驹针。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片烘挫。...
- 正文 年R本政府宣布喜滨,位于F島的核電站捉捅,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏虽风。R本人自食惡果不足惜棒口,卻給世界環(huán)境...
- 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望辜膝。 院中可真熱鬧无牵,春花似錦、人聲如沸厂抖。這莊子的主人今日做“春日...
- 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)忱辅。三九已至七蜘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間墙懂,已是汗流浹背橡卤。 一陣腳步聲響...
- 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像巧勤,于是被迫代替她去往敵國(guó)和親嵌灰。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
推薦閱讀更多精彩內(nèi)容
- 之前寫(xiě)過(guò)一篇關(guān)于Android組件化的文章颅悉,《Android組件化框架設(shè)計(jì)與實(shí)踐》沽瞭,之前沒(méi)看過(guò)的小伙伴可以先點(diǎn)擊閱...
- 上集回顧 上一篇文章解說(shuō)了模塊化以及組件秕脓,插件化的概念。模塊化是一種解決項(xiàng)目分層的思想儒搭,組件化和插件化分別是其不同...
- Android組件化項(xiàng)目地址:Android組件化項(xiàng)目AndroidModulePattern Android組件...
- 原文地址: http://www.reibang.com/p/f671dd76868f[https://www....
- Array.from() 能將類(lèi)數(shù)組(arguments,NodeList)吠架,可迭代對(duì)象(Set,Map),字符串...