CC框架實踐(2):Fragment和View的組件化

前言

本文將介紹如何在CC框架下實現Fragment和View的組件化。java

1、需求背景

在android組件化過程當中,你有沒有遇到這樣的問題:android

  • 單Activity + 多Fragment的架構下,如何進行Fragment的組件化?
  • 主界面上的Fragment太多,想用組件化進行管理,該怎麼作?
  • 一個功能模塊比較獨立,但在主界面使用了其中一個Fragment,如何解耦?
  • 對某些View進行了封裝或者自定義的View,功能比較獨立,是做爲基礎庫經過類依賴使用好仍是做爲組件使用比較好?若是要做爲組件使用,那要如何組件化?

2、現有的一些解決方案:

  • 在主app中依賴全部組件,因此在主app中可直接使用這些組件中的Fragment或View的類
    • 直接使用具體的類將產生耦合,違背了組件化的解耦目的
    • 組件之間的fragment引用也須要直接依賴,這樣就變成了一個庫而非組件
  • 使用ARouter來獲取Fragment對象來實現Fragment組件化
    • 因爲沒有Fragment的具體類型,只能調用到系統中Fragment的public方法,不能進行業務通訊
    • 因爲View的建立須要用到Activity對象(用Application對象會致使Activity設置的Theme樣式失效),沒法經過這種方式來獲取
  • 建立一個公共庫,供全部組件依賴,全部組件在初始化時,將組件內的Fragment和View註冊到公共庫中生成一個映射表。組件經過調用公共庫的映射表查找對應的Fragment或View的類
    • 跟用ARouter獲取Fragment同樣,在組件中無具體類型時沒法進行業務通訊
    • 若是要用於獲取View,其構造方法的參數列表調用方須要瞭解,在必定程度上也屬於類耦合
  • 使用ARouter的獲取Service方式實現,對外暴露服務,在公共庫中定義接口,提供建立、業務通訊相關的方法,在組件中實現此接口的具體功能,調用方經過動態獲取接口實現類來調用業務功能。這種方式能實現Fragment和View的組件化調用和業務通訊,實現的也比較優雅,但接口的管理成本有點高。
    • 接口放在公共庫中,通常用如下2種方式實現:
      • 爲每一個向外提供Fragment或View的組件額外建立一個公共庫,供須要調用的組件依賴(感受好麻煩,還不如直接依賴組件...)
      • 全部組件的這些接口統一放在一個公共庫中,供全部組件依賴。但這個庫的維護成本就比較高了,每次有新的接口或者原接口新增/修改方法都要修改這個庫。

3、快速瞭解CC

  • 是一套基於組件總線的組件化實施方案
  • 一靜一動,開發時運行2個app,業務環境始終是完整的:
    • 靜:主App (經過跨App的方式調用單組件App內的組件)
    • 動:正在開發中的單組件App (經過跨App的方式調用主App內的組件)
  • 支持漸進式組件化改造
    • 解耦只是過程,而不是前提

4、在CC框架中如何實現Fragment的組件化?

CC的參數和回調結果使用的數據結構是Map,在app內部能夠傳遞任何類型。數據結構

  1. 經過CC調用獲取組件中的Fragment對象架構

    1.1 組件調用方按以下方式調用,並從回調結果中獲取Fragment,例如:app

    Fragment fragment = CC.obtainBuilder("ComponentName")
            .build().call().getDataItem("key");
    if (fragment != null) {
        //show fragment
    }
    複製代碼

    1.2 組件實現方按以下方式設置結果,例如:框架

    CC.sendCCResult(cc.getCallId(), CCResult.success("key", new MyFragment()));
    複製代碼
  2. 與Fragment進行通訊ide

    組件化實施的主要目的之一是業務隔離:只暴露調用協議給外部(相似於app端與服務端的通訊接口),內部實現的更改對外部無影響。甚至組件的插拔和替換都不影響調用方(只要組件調用方作好組件調用失敗的降級處理,例如1.1示例代碼中的if (fragment != null) {...}。)組件化

    因此,Fragment中的具體業務邏輯應由組件自身內部來實現,在組件調用方(如:Activity)中經過CC調用組件暴露的接口來完成。post

    2.1 組件調用方將fragment對象及其它參數經過CC傳遞給組件,例如:ui

    boolean success = CC.obtainBuilder("ComponentName")
        .setActionName("updateTextView") //action名稱
        .addParam("fragment", fragment) //目標fragment對象
        .addParam("value", text) //設置參數
        .build().call().isSuccess();
    複製代碼

    2.2 組件中接收fragment對象及其它參數,並調用fragment對象的指定方法實現對應的業務,例如:

    @Override
    public boolean onCall(CC cc) {
        String actionName = cc.getActionName();
        if ("updateTextView".equals(actionName)) {
            MyFragment fragment = cc.getParamItem("fragment");//接收fragment對象
            if (fragment != null) {
                String text = cc.getParamItem("value", "");//接收其它參數
                fragment.updateText(text);//調用fragment的方法
                CC.sendCCResult(cc.getCallId(), CCResult.success());//回調結果
            } else {
                //回調錯誤信息
                CC.sendCCResult(cc.getCallId(), CCResult.error("no fragment params"));
            }
        }
        return false;
    }
    複製代碼

5、 View有沒有必要組件化?

答案是:對於一些封裝過的View、自定義View(特別是第三方自定義View)是有必要的。

理由是:組件化能很好的解耦,將業務實現徹底交給組件內部完成,只要接口協議不發生變化,實現方式發生改變時不會影響到使用方式。

網上不少組件化方案中,都是將自定義View(本身寫的或者第三方庫)做爲公共庫來使用。若是沒有作個適配層(Adapter)而直接使用自定義View的類,將會致使View的耦合度很高,下降系統的擴展性。

6、在CC框架中如何實現View的組件化?

與Fragment組件化同樣,經過CC獲取對象和業務調用。

惟一的差異是:在獲取View對象時須要將Activity對象傳給組件

View view = CC.obtainBuilder("ComponentName")
        .setContext(activity) //將activity對象傳給組件,用於View的初始化
        .build().call().getDataItem("key");
if (view != null) {
    //add view to container
}
複製代碼

總結


關於android的組件化文章通常都只是介紹如何進行Activity的跳轉及服務調用,對於Fragment的組件化一直沒有很好的解決,View的組件化幾乎沒有被提到。

本文介紹了在CC組件化框架下實現Fragment及View組件化的方式,爲android工程組件化的道路掃除一個障礙。

系列文章

CC:可關聯生命週期的android組件化開發框架

CC框架實踐(1):實現登陸成功再進入目標界面功能

CC框架實踐(2):Fragment和View的組件化

CC框架實踐(3): 讓jsBridge更優雅

相關文章
相關標籤/搜索