1. 程式人生 > >Android元件化之元件通訊

Android元件化之元件通訊

Demo地址:https://github.com/751496032/ComponentDemo
本文是續上一篇Android元件化方案實踐與思考文章一些思考,主要是針對元件間通訊,比如:

  • 每個元件如何初始化各自的資料
  • Activity間如何跳轉、Fragment例項獲取、訪問普通類
  • 如何在一個元件中通知另外一個元件資料變化

這些問題是我們在元件化過程中都會遇到問題,在專案中肯定遠遠還不止這些問題,在這樣我遇到的問題記錄下來,有不對的地方希望大家多多指點!!

元件資料初始化

常規下我們都會把一些庫、第三方SDK等等的初始化工作放在Application中初始化,在元件化思想中,每個業務元件是不存在任何依賴關係的,都可以單獨執行,是一個同級關係,每個元件都有一個Application,在元件合併組合時,在Mainfest只允許宣告一個Application類,哪如何做到初始化Main的Application,其他元件中的Application同步初始化資料,我的方案是:

1、在BaseApp中定義一個抽象方法,每個元件的Application都必須重寫該方法

public abstract class BaseApp extends MultiDexApplication {

    public abstract void initModuleApp(Application application);

}

2、接著每個元件的Application繼承於BaseApp,重寫initModuleApp方法,同時在其方法中初始化每個元件需要的資料,如下

public class HomeApp extends BaseApp {

    private Context mContext;

    /**
     * 在onCreate中初始化是元件獨立執行時用來初始化
     * 在合併組合時是不會呼叫onCreate
     */
    @Override
    public void onCreate() {
        super.onCreate();
        this.mContext=this;
    }

    /**
     * 合併組合時初始化資料
     * @param application
     */
    @Override
    public void initModuleApp(Application application) {
        mContext=application.getApplicationContext();
        Log.d(TAG,"HomeApp 初始化資料");
    }

這裡只貼一個元件的Application的程式碼,其他元件類似。

3、最後一步很重要,在Main的Application中通過反射獲取每個元件的Application例項,通過例項來呼叫initModuleApp函式,在這裡我定義AppConfig類用來管理每個元件的Application類名

public class AppConfig {
  public static final  String[] apps={"com.hzw.home.HomeApp",
                                        "com.hzw.cart.CartApp",
                                         "com.hzw.me.MeApp",
                                        "com.hzw.login.LoginApp"};
}

public class App extends BaseApp {


    @Override
    public void onCreate() {
        super.onCreate();

        initModuleApp(this);
    }

    /**
     * 通過反射呼叫每個元件的initModuleApp函式
     * @param application
     */
    @Override
    public void initModuleApp(Application application) {
        for (String appClassName:AppConfig.apps){

            try {
                Class<?> name = Class.forName(appClassName);
                BaseApp baseApp = (BaseApp) name.newInstance();
                baseApp.initModuleApp(application);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }

        }
    }
}

最後看看測試效果,確實達到我們想要的結果:
在這裡插入圖片描述

Activity如何跳轉、Fragment例項獲取、如何呼叫普通類的函式

這裡主要還是依賴阿里的ARouter框架來實現,官方的介紹:

ARouter:一個用於幫助 Android App 進行元件化改造的框架 —— 支援模組間的路由、通訊、解耦

除了ARouter還有ActivityRouter也可以實現元件的通訊,ActivityRouter是個人開源專案,這裡以ARouter為準。

Activity跳轉
1、添加註解:

// 在支援路由的頁面上添加註解(必選)
// 這裡的路徑需要注意的是至少需要有兩級,/xx/xx
@Route(path = "/test/activity")
public class YourActivity extend Activity {
    ...
}

2、發起跳轉

// 1. 應用內簡單的跳轉(通過URL跳轉在'進階用法'中)
ARouter.getInstance().build("/test/activity").navigation();

// 2. 跳轉並攜帶引數
ARouter.getInstance().build("/test/1")
			.withLong("key1", 666L)
			.withString("key3", "888")
			.withObject("key4", new Test("Jack", "Rose"))
			.navigation();

Fragment例項獲取

Fragment fragment = (Fragment) ARouter.getInstance().build("/test/fragment").navigation();

訪問普通類

比如說我們要在Home元件中的某個頁面中獲取Me元件中的某個屬性值,可以暴露服務的方式,為了Home元件提供內容,同樣也是基於ARouter來實現的:

下面獲取Me元件中的堅持總會看到不一樣文字為例
在這裡插入圖片描述

1、在Base基礎元件中,定義介面繼承於IProvider,其他元件通過該介面來呼叫需要的函式;

public interface IBaseProvider extends IProvider {

}


public class BaseProvider implements IBaseProvider{

    private String meText;

    @Override
    public void init(Context context) {

    }

    public void setMeText(String meText) {
        this.meText = meText;
    }

    public String getMeText(){
        return meText;
    }
}

2、接著在Me元件中實現該介面,通過宣告該類的路由路徑。

@Route(path = "/me/provider/text")
public class MeTextProvider extends BaseProvider {
    
}

3、在Me元件上初始化setMeText

BaseProvider provider = (BaseProvider) ARouter.getInstance().build("/me/provider/text").navigation();
provider.setMeText(mTvIntro.getText().toString());

4、在Home元件通過getMeText得到Me元件中屬性值,由此就完成了兩個業務元件間資料訪問。

 @Override
    public void onHiddenChanged(boolean hidden) {
        super.onHiddenChanged(hidden);
        if (!hidden){
            BaseProvider provider = (BaseProvider) ARouter.getInstance().build("/me/provider/text").navigation();
            String meText = provider.getMeText();
            mTextView.setText(TextUtils.isEmpty(meText)?"請先初始化Me元件":meText);
            Log.d("BaseProvider:: ",TextUtils.isEmpty(meText)?"請先初始化Me元件":meText);
        }
    }

這也是元件間通訊方式之一,有時候我們也可以通過事件匯流排的方式來實現元件通訊,具體還是要看你實現的功能了。