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);
}
}
這也是元件間通訊方式之一,有時候我們也可以通過事件匯流排的方式來實現元件通訊,具體還是要看你實現的功能了。