Android组件化之组件通信

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hzw2017/article/details/84204833

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);
        }
    }

这也是组件间通信方式之一,有时候我们也可以通过事件总线的方式来实现组件通信,具体还是要看你实现的功能了。

猜你喜欢

转载自blog.csdn.net/hzw2017/article/details/84204833
今日推荐