android module解耦組件化總體概述(推薦)
原由
移動(dòng)開(kāi)發(fā)中,隨著項(xiàng)目不斷的跌代,需求越來(lái)越復(fù)雜后。項(xiàng)目工程也越來(lái)越龐大。那么此時(shí)的分module的開(kāi)發(fā),則是必然的選擇了。在最終的組件化之路上,不妨把單一工程比如石器時(shí)代,那么接下來(lái)簡(jiǎn)單的拆分工程分多個(gè)moudle開(kāi)來(lái)就是銅器時(shí)代。
銅器時(shí)代之簡(jiǎn)單分module
演進(jìn)
由于從復(fù)雜的單工程拆分了多個(gè)module了,達(dá)到了代碼及資源的初步的隔離,或需求模塊的開(kāi)發(fā)人員,開(kāi)始專(zhuān)注于自己的需求模塊module的開(kāi)發(fā)了。但是隨著部分需求有相關(guān)性,需要相互調(diào)用時(shí)。那么問(wèn)題來(lái)了,在A(yíng)XXX module中
api project(':BXXX')
而在BXXX module中
api project(':AXXX')
這時(shí)出現(xiàn)了相互依賴(lài),首先編譯器會(huì)能不過(guò),會(huì)出現(xiàn)Circular dependency,循環(huán)相互依賴(lài)的問(wèn)題,這是絕不允許的。
為了解決上述的問(wèn)題,將AXXX module與BXXX module需要對(duì)外提供服務(wù)能力支持的,進(jìn)行封裝與抽象。將需要對(duì)外暴露接口/協(xié)議地方,對(duì)其抽象出接口出來(lái)。把些這接口獨(dú)立放在BaseXXXX module中,這樣AXXX module與BXXX module,都分別去
api project(':BaseXXXX')
通過(guò)BaseXXXX中間module通信去解決AXXX module與BXXX module相互依賴(lài)調(diào)用通信。
初步的解決方法
為了在BaseXXXX module中,搭建起AXXX module與BXXX module相互通信的橋梁,可以在BaseXXXX module 定義一個(gè)通信標(biāo)識(shí)接口:
/**
*
* 跨module通訊的 標(biāo)識(shí) interface接口
*/
public interface IModuleApi {
}
然后主要通過(guò)ModuleApiHelper進(jìn)行通信
public class ModuleApiHelper {
private static Map<Class<? extends IModuleApi>,IModuleApi> moduleApiMap = new HashMap<>();
private static Map<Class<? extends IModuleApi>,List<IModuleApi>> moduleApiListMap = new HashMap<>();
/**
* 跨module 注冊(cè)進(jìn) IKWModuleApi接口,及實(shí)現(xiàn)
* 通??梢栽?其它的module中 注冊(cè)此接口的實(shí)現(xiàn),在用的module中g(shù)etModuleApi拿到接口實(shí)現(xiàn)
* 這樣,用的module 不是 必須依賴(lài)compile其它module了
* @param clazz
* @param iModuleApi
*/
public static void register(Class<? extends IModuleApi> clazz, IModuleApi iModuleApi){
if (null != iModuleApi && null != clazz){
moduleApiMap.put(clazz, iModuleApi);
}
}
public static void unregister(Class<? extends IModuleApi> clazz){
if (moduleApiMap.containsKey(clazz)){
moduleApiMap.remove(clazz);
}
}
public static void register2List(Class<? extends IModuleApi> clazz, IModuleApi iModuleApi){
if (null != iModuleApi && null != clazz){
if (moduleApiListMap.containsKey(clazz)){
List<IModuleApi> iModuleApis = moduleApiListMap.get(clazz);
iModuleApis.add(iModuleApi);
}else{
List<IModuleApi> iModuleApis = new ArrayList<>();
iModuleApis.add(iModuleApi);
moduleApiListMap.put(clazz, iModuleApis);
}
}
}
public static void unregister2List(Class<? extends IModuleApi> clazz){
if (moduleApiListMap.containsKey(clazz)){
moduleApiListMap.remove(clazz);
}
}
public static void unregisterAll(Class<? extends IModuleApi> clazz){
unregister(clazz);
unregister2List(clazz);
}
public static <T extends IModuleApi> List<T> getModuleListApi(Class<T> clazz){
if (null != clazz){
if (moduleApiListMap.containsKey(clazz)){
List<IModuleApi> iModuleApis = moduleApiListMap.get(clazz);
return (List<T>) iModuleApis;
}else{
return null;
}
}else{
return null;
}
}
/**
* 獲取注冊(cè)綁定過(guò)來(lái)的IKWModuleApi 實(shí)現(xiàn)
* @param clazz
* @param <T>
* @return
*/
public static <T extends IModuleApi> T getModuleApi(Class<T> clazz){
if (null != clazz){
if (moduleApiMap.containsKey(clazz)){
return (T) moduleApiMap.get(clazz);
}else{
return null;
}
}else{
return null;
}
}
}
這樣比如在A(yíng)XXX module中將原有AServiceData類(lèi)是如下的:
public class AServiceData {
public String getSomeData(){
return "this is some data";
}
public void sayHello(){
System.out.println("hello");
}
}
改造成
public interface IAServiceData extends IModuleApi {
String getSomeData();
void sayHello();
}
public class AServiceData implements IAServiceData{
@Override
public String getSomeData(){
return "this is some data";
}
@Override
public void sayHello(){
System.out.println("hello");
}
}
將IAServiceData接口定義在BaseXXXX module 中。然后AXXX module中進(jìn)行register相應(yīng)的服務(wù)
public class AModuleService {
public void init(){
ModuleApiHelper.register(IAServiceData.class,new AServiceData());
}
}
這樣調(diào)用AModuleService的init方法,即可對(duì)IAServiceData服務(wù)進(jìn)行注冊(cè)了。然后即下來(lái),在BXXX module中進(jìn)行g(shù)etXXX得到服務(wù)即可調(diào)用相應(yīng)的方法了.
在任何需要此服務(wù)的方法可如下調(diào)用:
IAServiceData iaServiceData = ModuleApiHelper.getModuleApi(IAServiceData.class);
注意
1> register注冊(cè)時(shí)機(jī),需要越早越好,一般建議在各module的有類(lèi)似的application的onCreate時(shí)注冊(cè)最好。
2> IModuleApi與ModuleApiHelper,和各extends繼承IModuleApi接口的接口,需要放在中間通信BaseXXX Module中。各需要通信的module去 compile/api BaseXXX Module即可。
問(wèn)題
為了保證IModuleApi接口注冊(cè)有效,需要越早越好進(jìn)行注冊(cè)。這樣隨著項(xiàng)目越來(lái)越復(fù)雜,需要通信的地方越來(lái)越多。統(tǒng)一的ModuleApiHelper,注冊(cè)的地方將越來(lái)越多帶的問(wèn)題也多起來(lái)。
1> 注冊(cè)Map容器占用的內(nèi)存不斷的增多。
2> register注冊(cè)的地方不統(tǒng)一,有些放在各module的類(lèi)Application的onCreate中,有些可能是放在其它的類(lèi)中.
3> 不支持ui頁(yè)面的跳轉(zhuǎn),由AXXX module的AxxActtivy頁(yè)面跳轉(zhuǎn)到BXXX module的BxxActivity頁(yè)面中。
4> 不支持多進(jìn)程中應(yīng)用。
為了解決上述問(wèn)題,引入了蒸汽時(shí)代之ARoute到來(lái)。
蒸汽時(shí)代之ARoute
由于遍幅的原因,總體概述不詳細(xì)細(xì)述ARoute,下遍再剖析ARoute??傮w來(lái)說(shuō)在多module通信中解決了:
1> 解決了ui頁(yè)面的跳轉(zhuǎn)問(wèn)題。
2> 根據(jù)需要進(jìn)行register的問(wèn)題,且register通過(guò)靜態(tài)注解來(lái)的,所以register地方統(tǒng)一比如容易維護(hù)。
但是依然不能解決多進(jìn)程中的應(yīng)用。
電器時(shí)代之Andromeda
Andromeda解決了多進(jìn)程,跨進(jìn)程ipc之間的通信過(guò)程,同樣也支持單進(jìn)程的通信...
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。。
相關(guān)文章
Android ListView優(yōu)化之提高android應(yīng)用效率
android listview優(yōu)化做的好是提高androoid應(yīng)用效率的前提條件,本文給大家介紹Android ListView優(yōu)化之提高android應(yīng)用效率,對(duì)android listview優(yōu)化相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧2015-12-12
android創(chuàng)建手勢(shì)識(shí)別示例代碼
使用一些瀏覽器或者輸入法應(yīng)用時(shí)會(huì)有一些手勢(shì)操作,還可以自定義手勢(shì)。這些神奇的操作是怎么做的呢?這一篇重點(diǎn)記錄手勢(shì)的識(shí)別和創(chuàng)建2014-01-01
Ubuntu 14.04下創(chuàng)建Genymotion安卓虛擬機(jī)的步驟詳解
Android 模擬器一直以速度奇慢無(wú)比著稱(chēng),基本慢到不可用。本文介紹我一直在用的 Genymotion,速度不亞于真機(jī)。而且功能齊全,使用簡(jiǎn)單。下面這篇文章主要介紹了Ubuntu 14.04下創(chuàng)建Genymotion虛擬機(jī)的步驟,需要的朋友可以參考下。2017-03-03
Android之禁止ViewPager滑動(dòng)實(shí)現(xiàn)實(shí)例
這篇文章主要介紹了Android之禁止ViewPager滑動(dòng)實(shí)現(xiàn)實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-05-05
Android實(shí)現(xiàn)關(guān)機(jī)與重啟的幾種方式(推薦)
這篇文章主要介紹了Android實(shí)現(xiàn)關(guān)機(jī)與重啟的幾種方式(推薦)的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07
Android Studio使用ButterKnife和Zelezny的方法
這篇文章主要為大家詳細(xì)介紹了Android Studio使用ButterKnife和Zelezny的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-04-04
Android SeekBar實(shí)現(xiàn)禁止滑動(dòng)
這篇文章主要為大家詳細(xì)介紹了Android SeekBar實(shí)現(xiàn)禁止滑動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-03-03
Android實(shí)現(xiàn)退出時(shí)關(guān)閉所有Activity的方法
這篇文章主要介紹了Android實(shí)現(xiàn)退出時(shí)關(guān)閉所有Activity的方法,主要通過(guò)自定義類(lèi)CloseActivityClass實(shí)現(xiàn)這一功能,需要的朋友可以參考下2014-09-09

