組件化實踐詳解(二)

在上一篇文章《組件化實踐詳解(一)》中咱們介紹了組件化實踐的目標和實踐步驟,本文繼續說說關於組件化實踐遇到的問題及思考。android

本文概述

一、組件內的架構設計

這條原本我是不想寫的,可是不少組件化的文章裏都會費盡心思的寫組件內的架構設計。bash

那我也談一談個人見解:首先回歸初心,想一想組件化的目的,爲了各個業務組件能夠單獨運行。劃重點:目的是單獨運行,把以前在App Module的代碼挪到本身單獨的Module,而後可以獨立運行;而不是大面積重構!!我也相信對於大部分團隊,實際上並無不少的時間去作重構,尤爲是在作組件化的過程當中同時大面積重構,肯定作了風險評估嗎微信

對於組件化的總體設計,須要遵循制定的規則,可是對於組件內的架構設計,實際上不須要特殊的要求,代碼你愛怎麼寫就能夠怎麼寫,無論你使用MVC、MVP仍是MVVM,根據各自狀況合理選擇就行了。這個話題原本就不屬於組件化項目的範疇。網絡

二、調試方式

假如以前的幾步咱們都順利完成,如今整個Project已經變成了下圖整個樣子。架構

那咱們的Module要怎麼才能跑起來呢?app

  1. 咱們建立Module的時候若是選擇的是Application工程,毋庸置疑確定是能跑起來的,可是卻沒有辦法被真正的Host宿主引用了
  2. 建立Module的時候選擇的是Library工程,能夠被引用可是沒法本身單獨運行

兩者結合呢?藉助馮大大在MDCC上的分享,將Module分爲兩個模式:Release模式和Debug模式,Release模式下做爲Library,供宿主依賴;而在Debug模式下則做爲Application工程,本身單獨運行框架

build.gradle中根據gradle中的一個屬性值來判斷處於哪一種模式下:maven

if (isDebug.toBoolean()) {
        apply plugin: 'com.android.application'
    } else {
        apply plugin: 'com.android.library'
    }
    
     sourceSets {
        main {
            if (isDebug.toBoolean()) {
                manifest.srcFile 'src/main/debug/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/release/AndroidManifest.xml'
            }
        }
    }   
複製代碼

在Release中的AndroidManifest配置默認啓動的主Activity。組件化

這樣一來調試的問題也就解決了。可是實際上這僅僅是一個Demo雛形,咱們思考幾個帶出來的問題:gradle

  1. 若是我這個業務組件涉及了別的好幾個Module,也就是我本身使用Debug模式運行的時候別的Module須要使用Release模式,那麼每一個Module都須要一個單獨的變量去控制,Module過多致使變量過多,出錯可能性陡增
  2. 直接的源碼依賴:假如你們在一個分支上開發不一樣的組件,有極大可能會致使衝突或者調用異常致使影響研發效率;固然確定有人會說通常不會在一個分支開發,確實,但作了組件化以後分支數實際上是能夠變少的
  3. 若是是Host直接源碼依賴子Module,那當子Module做爲Application工程運行的時候一旦你Build項目,那各類美如畫的報錯讓你苦不堪言

如何對這個狀況作優化:各個獨立Module提供穩定版本的aar

  • 單獨的業務組件開發完成以後,記錄一個版本號同時提供一個穩定的aar
  • 別的依賴模塊直接去compile須要的業務組件的aar便可
  • Host宿主則是compile這些業務組件穩定的aar
  • 依賴於穩定的aar,那麼本身的業務組件開發並不會影響到別人,並且Build的時候宿主也不會出錯
  • 針對衆多的aar包,最好建一個maven倉庫來統一管理
  • 生成及上傳aar包這步,能夠寫個腳本幫忙生成及上傳

三、工程化經驗

如下介紹些關於工程化的經驗

3.1 Application

部分業務組件必定會遇到依賴一些三方組件須要提早初始化的狀況,正常咱們的作法都是在應用的Application中作的。此時咱們在獨立的Module開發,沒有了應用的Application,那麼能夠本身建立一個Module的Application,如下提幾種實現的思考

  1. Module的Application只工做在Debug模式下,而在宿主中也一樣註冊須要的三方組件,Release模式下沒有這個Application則不會重複註冊

  1. Module的Application同時工做於這兩種模式下,可是真正打包生成Apk以後實際系統承認的只有App的Application,而別的Module Application只是被系統認爲是一個沒有特殊意義的普通類。那咱們能夠在真正的Application方法調用的時候經過反射調用Module Application的相應方法

  1. 源於第二種方案,區別在於將Module組件中的初始化工做,延遲到組件使用的時候纔去初始化,好處就是使用時才加載

備註:而怎麼判斷調用業務Module呢?兩個場景:UI跳轉或者方法調用,這兩種判斷可使用路由框架來協助。

3.2 Application與Tinker的兼容

Tinker做爲熱修復的可靠解決方案,想必不少App都會集成,可是Tinker集成稍繁瑣的地方就在於:爲了確保Application也能修復,須要改造Application,改造完成以後打的包出來真正的Application已經被修改,而寫上了咱們邏輯的Application實際上變成了一個普通類,只是相應方法被真正的Application調用

那我想把Tinker這個模塊也單獨做爲一個Module來使用,能行嗎?首先來思考一個問題:Application要在哪裏,Library中仍是Host

答案是Library中,由於各個Module中可能會存在不方便獲取Context的場景,解決方案之一就是使用Application的Context。假設Application放在Host中,那Module確定是沒法使用的。固然剛剛咱們說到Module本身的Application,可是別忘了若是Module沒有呢?

把Application放到Library中也不是說移就能移:

  • 正常狀況下咱們會發現Host Application中也有一大堆的邏輯或者是組件初始化,而這些組件要全被移出去還須要 a long long time
  • 代碼中有一大堆經過Host Application拿到的Context,如今突然移出去,一定一大堆報錯

面對如此抉擇,那究竟是移仍是不移?一個好方法是原來Host的Application只作較小改動:並不移出來以前的各類邏輯和組件,而是做爲一個普通類,在Library中的Application方法執行時去回調相應Host Application的方法;隨後在組件化的過程當中逐漸的移出來這些業務和組件。這樣的改動成本最小又知足了當下的須要

3.3 資源衝突

在拆分出來多個Module或者新建Module進行開發,新建資源的時候可能會有命名的衝突,對Gradle熟悉的同窗可能會表示使用resourcePrefix來進行限定,可是坦白說效果通常,卻是不如在編碼規範中加上一條以相應Module的標示做爲命名的前綴

3.4 ButterKnife的使用

ButterKnife——相信不少同窗都用過,這是一個註解框架,通常在綁定View的時候使用,減小了不少無心義的代碼。在正常開發中咱們用起來也是6的飛起!然而當ButterKnife跑在Library工程中的時候各類Build失敗就出現了:緣由在於Android Library中的R文件字段並非常量,Module在Debug模式下是Application工程能夠開心玩耍,等真正集成的時候切換回Release模式就呵呵噠了

在ButterKnife8.0以後也支持了在Library中使用,解決方式就是同時生成了一個R2,這個就是常量,於是能夠在Library工程中使用。

推薦使用Android ButterKnife Plugin Plus插件,方便的一鍵生成而後將R更改成R2;或者本身仿照去寫一個AS插件,直接生成R2

備註:同時注意R2只能使用在註解中,於是點擊事件要寫成這樣:

@OnClick(R2.id.tv_back_selerole)
    public void onClick(View view) {
        if (view.getId() == R.id.tv_back_selerole) {
            dealBack();
        }
    }
複製代碼

3.5 避免過大的基礎庫

這個問題的引出是在組件化相對成熟的階段,已經初步完成了咱們的預期目標,可是細化的過程當中逐漸意識到一個問題:Library庫愈來愈大,其實單獨的一個Module並不會須要那麼多的組件,可是單獨Module運行的時候仍是被引用上了,也會拖慢單獨Module的執行速度

因而咱們提出了另一個名詞:去中心化。將基礎庫進行細粒度的拆分,將開發中必定會用到的例如網絡請求、EventBus、公共類等放在了Library中,而將別的不經常使用三方組件如地圖等移出去,只供須要的Module去依賴,而普通的Module則只依賴經常使用的Library。

這樣能夠有效的避免Library逐漸變得膨脹,也給各Module只去依賴本身須要的特定Library能力

四、組件化成效

歷經千辛萬苦咱們對項目作了組件化實踐,那究竟收穫了哪些好處呢?

  • 代碼結構層次清晰明瞭;
  • 組件間界限清晰、有明確邊界,低耦合;
  • 開發過程體驗好,快速編譯;
  • 版本週期內沒有動到的組件快速回歸;
  • 方便A/BTest;

廣告時間

今日頭條各Android客戶端團隊招人火爆進行中,各個級別和應屆實習生都須要,業務增加快、日活高、挑戰大、待遇給力,各位大佬走過路過千萬不要錯過!

本科以上學歷、非頻繁跳槽(如兩年兩跳),歡迎加個人微信詳聊:KOBE8242011

歡迎關注
相關文章
相關標籤/搜索