Android 组件化架构-简谈

说在前面:

随着业务的增加,由于单一工程下业务全都集合在主工程下,而导致业务间相互交错的依赖耦合越来越严重,那么就可能出现动一触千的现象,这时候将业务按照功能的不同抽离出来就显得迫在眉睫。

了解组件化

在了解组件化之前,我们需要先了解模块化。
模块化就是将整体业务集合按照功能的不同,抽离到不同的模块中,这样做的好处就是在团队协助中能够较好的区分各自负责的功能模块、也能使得整个工程显得不是那么庞大和复杂。
但是在工程结构不断扩大的情况下,模块之间的耦合也会变的错综复杂,这时候我们就需要将模块化再次升级,使得各模块之间进行解耦,组件化的需求也就由此产生。
理想的组件化架构大概可以分为四层 : 壳工程、业务层、业务基础层、基础层。
其中壳工程依赖所有业务层组件和通用模块集成作为应用程序入口。
业务层依赖与本身业务相关的业务基础层组件,但是各业务层组件之间不会进行依赖,然后就是业务基础层组件依赖基础层组件。
总的来说就是上层依赖下层,并且下层几乎不改动,而是根据业务的需求改动上层。
组件化可以使得各业务模块相互解耦,没有直接依赖关系。并且可以独立作为app运行调试。

组件化我们需要解决的问题

  • 既然组件可以作为app独立运行,那是怎么实现的呢?
  • 业务组件之间没有直接耦合,那怎么通信呢?
  • 如果遇到某一业务需要调用另一个业务的方法或服务怎么办呢?
  • 如何获取到fragment实例呢?
  • 由于壳工程已经依赖了所有的业务组件,那么业务组件就无法依赖壳工程了,那我需要使用应用的application怎么办?

接下来我们就一个问题一个问题的开始解决

业务模块独立调试

!!由于是我只在单一工程下做过这个,所以咱不谈多工程下该怎么做(想要知道的可以点击这篇文章的最下面的参考链接)
在这之前我们先了解一下两种不同的插件,及其作用:

  • application插件 : com.android.application
  • library插件 : com.android.library
    当模块使用application插件时会被构建成APK包
    而当用library插件会被构建成ARR包
    我们知道AndroidStudio 使用的Gradle进行构建项目的,那么Gradle会根据插件的配置不同构建不同的包,所以如果想要独立调试那就得先把业务组件的library插件改为application插件。
    这里为了方便独立调试,我们可以在根目录的gradle.properties目录下建立一个字符串用来标记是否独立调试然后根据该字符串的值改变到相应的插件
//gradle.properties中 能被所有module的build.gradle读到
isModule = true

//模块build.gradle中
if(isModule.toBoolean()){
apply plugin : 'com.android.library'
}else{
apply plugin : 'com.android.application'
}

我们知道,一个app不但要是application 模式下,还需要设置一个启动页面,和设置applicationid。那我们还得动态的去配置androidmanifest和applicationid。
同理我们可以根据上面模式去套,这里就不贴代码了。当然用于独立调试的AndroidManifest.xml文件,我们需要去指定它的位置,我们可以利用manifest.srcFile 去指定路径。
注意!! 我们改变isModule的值后记得同步工程哈

不同业务组件间的页面跳转

这里我选择的是阿里开源的Arouter方案,这里给大家贴一个入口,具体使用自己去看,我们可以利用该路由方案实现页面间的跳转,就如同使用startActivity一样。入口

不同业务组件间的通信

比如我在A页面(属于A业务组件)想要获取B页面(B业务组件)中的一些属性值,那我们该怎么办呢?这个也是比较好办的,我们可以将外部可能用到的服务暴露给外部,这也叫服务暴露组件。
在该组件中我们可以存放一些服务接口、实体类、路由信息和方便服务调用的util等。
服务的提供方依赖该组件,并且提供接口的实现
服务的调用方只需要依赖服务暴露组件,同过util调用服务。
接口的实现注入也是同过Arouter实现的
现在我们在开始实践一个
首先我们在暴露组件中定义一个实体类和一个服务接口继承Iprovider (这里必须继承Iprovider 这是为了后续的Arouter注入)

public class Info{
	public int count;
}
public interface IService extends IProvider {
    Info getInfo();
}


然后我们定义一个路由表,包含对外提供跳转的页面、服务的路由地址,注意后面服务提供的组件必须使用该路由信息去构建服务的实现路由

public interface RouterTable {

    /**
     * 页面
     */
    String PATH_PAGE_CART = "/***/Activity";

    /**
     *服务
     */
    String PATH_SERVICE_CART = "/***/service";

}

然后我们实现一个便于外部调用的Util

public class ServiceUtil {

    /**
     * 跳转页面
     * @param param1
     * @param param2
     */
    public static void navigatePage(String param1, String param2){
        ARouter.getInstance()
                .build(RouterTable.PATH_PAGE_CART)
                .withString("key1",param1)
                .withString("key2",param2)
                .navigation();
    }

    /**
     * 获取服务
     * @return
     */
    public static ICartService getService(){
        return (ICartService) ARouter.getInstance().build(RouterTable.PATH_SERVICE_CART).navigation();
    }

    /**
     * 获取属性
     * @return
     */
    public static CartInfo getCartProductCount(){
        return getService().getInfo();
    }
}


然后我们开始实现服务提供方的组件
这里第一件事就是我们需要依赖上面暴露的服务组件
然后我们开始完成上面的具体实现
建立我们要跳转的页面 (特别注意 记得用@Route注解标识路由路径,并且这个路径是从上方路由表获得)

@Route(path = RouterTable.PATH_PAGE_CART)
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

然后开始实现服务(特别注意 记得用@Route注解标识路由路径,并且这个路径是从上方路由表获得)

@Route(path = RouterTable.PATH_SERVICE_CART)
public class ServiceImpl implements IService {

    @Override
    public CartInfo getProductCountInCart() {
    	//这里实际项目中 应该是 请求接口 或查询数据库
        Info info = new Info();
        info.count = 666;
        return Info;
    }

    @Override
    public void init(Context context) {
        //初始化工作,服务注入时会调用,可忽略
    }
}

然后服务调用者组件只需要依赖服务暴露组件,皆可实现业务需求了。
当然除了上面这种方式,我们还可以利用总线等方式去完成这个需求,但是我没用过,咱就不写了,具体想看咱也提供一个入口

获取Fragment实例

相信根据上面的讲解,Fragment的获取也能get到了,其实也是利用Arouter,我们只需要在暴露服务组件中的路由表中再添加一个路由项,然后在提供服务的组件方中实现,并加上@Route(path = RouteTable.****)直接和activity一样调用就行,这里不贴代码了。

Application

在开发过程中我们可能会在很多地方需要使用到Application的实例。或者需要在application的oncreate方法中进行初始化。但是我们又没依赖壳工程,也不能依赖壳工程,那该怎么办呢?
其实是有很多的解决方法的:
比如说直接使用反射获取、或者说用网易课堂中给出的方法(本质也是利用到了反射)
我所在项目中这样实现的:
在通用组件下建立一个Iapplication继承 application。然后在app模块下创建一个myapplication 继承 Iapplication。具体操作我给个代码:

//通用组件下
open class WcApplication:Application() {
 companion object{
        @JvmField
        var instance: Application? = null
    }
 override fun onCreate() {
        super.onCreate()
        instance = this
       //当MyApplication运行时会调用这个方法
       //但是this表示的并不是WcApplication而是MyApplication
       //亲测可用!!
    }
    
 }

再来一个app模块下:

class MyApplication:WcApplication(){
   
    override fun onCreate() {
        super.onCreate()
    }
}

给出参考地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值