Demo地址:https://github.com/751496032/ComponentDemo
本文是续上一篇Android组件化方案实践与思考文章一些思考,主要是针对组件间通信,比如:
这些问题是我们在组件化过程中都会遇到问题,在项目中肯定远远还不止这些问题,在这样我遇到的问题记录下来,有不对的地方希望大家多多指点!!
常规下我们都会把一些库、第三方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();
}
}
}
}
这里主要还是依赖阿里的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来实现的:
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);
}
}
这也是组件间通信方式之一,有时候我们也可以通过事件总线的方式来实现组件通信,具体还是要看你实现的功能了。