一肖中特算数计算公式:如何優雅的實現自己的Android組件化改造? [復制鏈接]

2019-5-22 18:27
iyifei 閱讀:220 評論:0 贊:0
Tag:  

本篇文章的主要目的:

  • 致富之地一肖中特 www.qcfmo.icu 幫助正在對項目進行組件化改造或者想建立組件化項目架構的小伙伴,更好的認識組件化本質。

  • 目前組件化的框架眾多,說的天花亂墜的,其本質來說其實都差不多,閱讀本文以后,讀者甚至可以摒棄這些開源框架,根據自己的項目特點,輕松構建自己的組件化框架。

  • 幫助想學習和了解組件化框架,并嘗試動手寫自己的開源框架的小伙伴們

什么是組件化?

在平時的開發過程中,隨著項目需求的增加,app支持功能越來越多,如果沒有組件化的思想,代碼會越來越臃腫。導致的問題也會越來越明顯,比如一個很小的需求變化,可能會導致代碼的“牽一發動全身”問題,甚至會出現很多隱藏的bug?;夠岬賈攣こ殺駒嚼叢礁?,團隊協作低效,問題邊界不清晰。

于是,很多團隊開始有了代碼解耦的想法,但是面對如此復雜的項目,又不敢輕易變更其中的代碼結構,如何順利的解耦就成了很多團隊難以入手的問題。甚至由于業務的不斷迭代,導致代碼解耦的問題遙遙無期。

當然,作為一位合格的App架構師,遇到再難的問題也會迎難而上。于是便開始對APP整體項目結構進行分析,制定解耦方案。通常情況下,解耦的最佳思路就是根據業務邊界對代碼結構進行劃分。比如說某APP里面包含了IM、直播、內容展示等等業務場景,于是從架構的角度來說,整個APP的架構應該是如下圖所示:

圖片描述

這種架構思路上很清晰,對應到我們Android代碼結構,就是根據這些業務邊界,拆分成不同的module,module之間沒有直接的引用和依賴,代碼完全解耦。作為團隊開發成員也有很清晰的業務邊界,代碼維護成本大大降低,開發效率也會明顯提高,應該是一個很不錯的方案。

所謂的組件化其實就是根據業務邊界對代碼進行解耦,不同的業務對應不同的module,這些module相互獨立,可以獨自作為一個app進行開發并獨立運行,合并時可以打包到一個整體的app中,實現完整的app功能。

如何優雅的進行組件化?

那么問題來了,以上的架構的確是非常不錯的選擇,但是實際的業務中,很難有個清晰的邊界,并且業務與業務直接總會有銜接的地方。如果使用以上的架構,那么這些不同的module之間又該如何進行調用呢?

在我們Android系統中,進程是一個獨立程序,每個進程都具有自己的虛擬機 (VM),應用代碼是在與其他應用隔離的環境中運行,進程直接的通信主要是基于Binder機制。為什么要提Binder,首先Binder是Android系統的中非常重要的實現機制,而我們組件化代碼耦合的問題也可以借鑒其實現原理。接下來我簡單的介紹一下Binder機制,先總體看一下Binder架構圖:

圖片描述

可以看出Binder是一個典型的CS架構,進程間的通信基于ServiceManager這個大管家,Client進程從ServiceManager中獲取Server進程的一個遠程代理,進行通信。為了讓大家更直接的理解,我從代碼層面上來簡單描述一下這個過程。比如我們啟動一個Activity時,需要ActivityManagerService(AMS)這個服務來進行管理,而AMS運行在SystemServer中,那么如何獲取這AMS呢,我們從源碼來分析(以下源碼android-28中):

public static IActivityManager getService() {
    return IActivityManagerSingleton.get();
}

private static final Singleton<IActivityManager> IActivityManagerSingleton =
    new Singleton<IActivityManager>() {
         @Override
         protected IActivityManager create() {
         //通過ServiceManager.getService獲取到AMS的代理IActivityManager
         final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
         final IActivityManager am = IActivityManager.Stub.asInterface(b);
         return am;
         }
};

app中通過ServiceManager.getService獲取到遠程進程中服務的代理,只需要指定服務的name就可以。

Binder機制就不展開講解,如果想了解更多的同學,可以加入到ARetrofit的QQ群中@我進行交流。接下來我們再回到“如何優雅的進行組件化”這個問題上。

在了解Binder機制后,對于我們組件化過程中解耦代碼如何通信,其實也可以采用類似的機制。當然我們的module之間并沒有跨進程,不會有跨進程通信的問題。

我們可以將圖1中的每一個module想象成一個服務,那么module之間的通信其實就類似于服務之間的通信。而服務之間的通信其實也不需要直接進行類的引用,只需要拿到另一個module的服務代理,通過這個代理進行通信。這里又出了一個新的問題,如何實現提供代理服務的代理管家呢,其實這也類似于Binder里面的ServiceManager,用以下這張架構圖來說明:

圖片描述

上圖中IM module注冊自己的IM服務到ServiceManager中,直播 module想要和IM module只需要獲取IM的服務代理就可以進行操作。注冊的過程,對應到實際的代碼中,其實就是中ServiceManager這個管家的Module中聲明自己的服務接口,并在自己的module中實現這一接口。其他module只需要在運行時拿到接口實現類的實例對象就可以完成這一過程了,這一部分其實可以參考ARetrofit README中 四 高階用法中登錄服務接口的聲明與注冊過程就可以了解。

當然,這篇文章不僅僅讓大家了解別人已經開源好的框架,其實類似的框架很多,如ARetrofit 、ARouter、CC等開源,無關star量,這都是開源早晚和推廣的問題,其實本質上都是基于以上的原理,區別就是上層的封裝的問題,最終呈現的API是否簡潔,是否符合自己的要求,能否直觀的進行代碼維護。

這里我將帶著大家動手一起實現自己的ServiceManager管家。

第一步,我們在ServiceManager中注冊不同module的服務接口,如下:

public interface ILoginManager {
    void login();
    User getUser();
}

第二步,在Login Module中實現該接口,如下:

@Inject //需要自動注入服務的聲明
public class LoginManagerService implement ILoginManager {
    @Override
    void login(Activity activity) {
       Intent intent = new Intent(activity, LoginActivity.class);
       activity.startActivity(intent);
    }

    @Override
    User getUser(CallBack callback) {
        //...網絡或者  或者  本地數據庫 等回去異步返回或者同步返回結果
        
    }
}

第三步, 在直播 Module中跨Module獲取ILoginManager服務實例對象,這里需要通過Android Studio自動注入框架[AInject]AInject(https://github.com/yifei8/AInject),完成跨Module自動注入流程,可參考(https://github.com/yifei8/AInject)[AInject]用法,具體實現如下:

 public class ServiceManager implements InjectContract {

  private static class ServiceManager {
      private static final ServiceManager instance = new ServiceManager();
  }

  static ServiceManager getInstance() {
      return InstanceHolder.instance;
  }
  
  /**
    * @Fixme 這里建議使用實現LRU算法的列表存儲
    */
  List<Object> services = new ArrayList();

 /**
   *
   * "@Inject" 注解標示的class 最終都會注入到該"@IMethod"注解標示過的方法中
   *  注:"@IMethod"注解標示過的方法將由編譯器自動注入實現代碼,注入最終的代碼如下如:
   *
   * @IMethod
   * public void iMethodName() {
   *       injectClass("injectClassName1")
   *       injectClass("injectClassName2")
   *       injectClass("injectClassName3")
   *       injectClass("injectClassName4")
   * }
   *
   * 用戶可以在該方法中通過反射完成自己的業務需求
   * @param className class name
   */
  @IMethod
  public void startInject() {
     

  }

  @Override
  public void injectClass(String serviceClassName) {
       services.clear()
       services.add(className);
  }

 /**
  * 獲取登錄服務,可在任意Module直接獲取該服務的實例化對象
  */
  public static ILoginManager getILoginManager() {
        if (getInstance().service.size() == 0) {
   getInstance().startInject();
        }
        for (String className: getInstance().services) {
           try {
    Class<?> clazz = Class.forName(className);
    Object obj = clazz.getConstructor().newInstance();
    if (obj instanceof ILoginManager) { 
         return obj;
    } else {
         obj = null;
    }
} catch (Exception e) {
  e.printStackTrace();
           }    
        }
        return null;
  }
}

其實就是這么簡單,一個組件化的框架就完成了。

看到這里的小伙伴們,大概已經理解了如何進行解耦Module直接的通信工作了吧。想想平時有沒有遇到其他關于高耦合的代碼需要解耦的,都可以參考這種思路哦。

組件化并不需要一蹴而就的

前面教大家如何進行組件化,已經如何實現組件化,其實還忽略了一個非常重要的問題,就是如何對現有的項目進行組件化。現有的項目一般都已經累計了很多代碼量,如果一次性根據業務進行拆解處理,解耦合顯然是不合實際的。那么到底該怎么做呢?

其實有了以上自定義的組件化框架ARetrofit框架,API使用非常簡潔),其實組件化并不是一個版本就需要完成的。組件化的第一步當然還是根據業務邊界來架構自己的APP框架,不同的Module中聲明好自己的服務。而組件化的工作可以拆分到不同的迭代版本中,對于新增的業務明確到對應的業務Module中開發,對應老的業務代碼如果耦合度比較高的,不建議直接修改邏輯,可以先將這部分代碼耦合的地方抽象到服務接口中,通過服務調用來實現調用過程。并在未來的版本中逐步進行剝離解耦最終實現真正的代碼隔離,以服務的形式完成業務間的交集部分。

組件化最佳實踐

小結

前面講了很多,我們再回到主題,相信大家對于“如何實現自己的Android組件化改造”應該有了很清晰的步驟和流程來吧。此外僅代表個人的一些拙見,如果意見或者建議歡迎進ARetrofit賜教。


我來說兩句
您需要登錄后才可以評論 登錄 | 立即注冊
facelist
所有評論(0)
領先的中文移動開發者社區
18620764416
7*24全天服務
意見反?。[email protected]

掃一掃關注我們

Powered by Discuz! X3.2© 2001-2019 Comsenz Inc.( 致富之地一肖中特 )

pk10全天免费手机计划 老时时开奖结果记录 美女捕鱼游戏手机版 时时彩彩神通免费版下载 双色球网上投注app 控制手机 幸运飞艇倍投7期 掷骰子比大小规则 后三组六杀号稳赚方案 时时彩时时彩定位胆稳赚技巧 足球怎么稳赚不赔 余额宝为什么稳赚不赔 这样买彩票你会稳赚不赔 免费黑客棋牌透牌器合集 3分快3计划软件下载 哪里有快三计划软件下载