YDL Android 组件化实践与拓展 (1) - 基础功能

2020-04-28  本文已影响0人  孔睿

组件化概述

问:什么是组件,什么是组件化?

答:在软件开发领域,组件(Component)是对数据和方法的简单封装,功能单一,高内聚,并且是业务能划分的最小粒度。举个我们生活中常见的例子就是电脑主板上每个元件电容器件,每个元件负责的功能单一、容易组装、即插即拔,但作用有限,需要一定的依赖条件才可使用。

问:组件化、模块化容易混淆,两者区别又是什么?

答:模块化就是将一个程序按照其功能做拆分,分成相互独立的模块,以便于每个模块只包含与其功能相关的内容,模块我们相对熟悉,比如登录功能可以是一个模块,搜索功能可以是一个模块等等。而组件化就是更关注可复用性,更注重关注点分离,如果从集合角度来看的话,可以说往往一个模块包含了一个或多个组件,或者说模块是一个容器,由组件组装而成。简单来说,组件化相比模块化粒度更小,两者的本质思想都是一致的,都是把大往小的方向拆分,都是为了复用和解耦,只不过模块化更加侧重于业务功能的划分,偏向于复用,组件化更加侧重于单一功能的内聚,偏向于解耦。

问:组件化能带来什么好处?

答:简单来说就是提高工作效率,解放生产力,好处如下:

实践难点

组件间通讯

常见组件通讯方式

主流方式

引入BaseModule放置所有对外接口,组件层的模块都依赖于基础层,从而产生第三者联系,这种第三者联系最终会编译在APP Module中,那时将不会有这种隔阂,那么其中的Base Module就是跨越组件化层级的关键,也是模块间信息交流的基础。

缺点

这种方式的问题在于因为所有的业务组件对外接口都定义在BaseModule中,所有业务组件都依赖BaseModule,那么无论是修改还是新增变动都会涉及到整个项目层面。并且无论Module 2 组件是否使用到Module 1组件的对外功能都会引入Module 1 组件所有的对外接口,增加了业务组件代码之间的关联性,模糊了各业务组件的职责边界。

image

优化方式

每个组件声明自己提供的服务 Service API接口,声明完成后抽取API到独立组件中。组件业务层依赖API层,并实现接口功能并注册 Service 实现到一个统一的路由 Router 中去。如果要使用某个组件的功能,只需要依赖该组件API层后向Router 请求这个 Service 的实现,具体的实现细节我们全然不关心,只要能返回我们需要的结果就可以了。

image

实践原理

步骤

实践过程

1. 定义组件配置信息

完整版 modular.gradle 文件

modular {
    packageName "com.ydl.other"
    // 模块发布需要的参数
    publish {
        modules {
          //发布信息
          groupId = "com.ydl"
          artifactId = "m-other-module-xxxx"
          // 上报的业务模块 aar 包的版本号
          version = "0.0.1"
        }

        api {
            //发布信息
            groupId = "com.ydl"
            artifactId = "m-other-api"
            // 上报的 API 层 aar 包的版本号
            version = "0.0.1"

            // API 层打包时需要引入的依赖
            apiDependencies {
                implementation "com.google.code.gson:gson:2.8.2"
            }
        }
    }
}

2. 创建 Gradle Plugin 读取配置信息

项目结构

image

核心代码

                          //默认引入项目目录下的modular配置文件
                project.allprojects.each {
                    if (it == project) return
                    Project childProject = it
                    def modularScript = new File(childProject.projectDir, 'modular.gradle')
                    if (modularScript.exists()) {
                        modularExtension.childProject = childProject
                        project.apply from: modularScript
                    }
                }

3. 生成组件发布任务

使用

任务列表

image

组件目录

<img src="https://ww1.sinaimg.cn/large/b89b3521ly1ge89m66t2nj20k20qcdg0.jpg" alt="image-20200427132340054" style="zoom:50%;" />

接口定义

/**
 * Created by haorui on 2019-10-10.
 * Des:
 */
public interface UserService extends IProvider {
    UserInfo getUser();
}

接口实现

/**
 * Created by haorui on 2019-10-10.
 * Des:
 */
@Route(path = "/user/UserService")
public class UserServiceImpl implements UserService {
    public UserServiceImpl() {
    }
    @Override
    public UserInfo getUser() {
        return new UserInfo("from user");
    }
    @Override
    public void init(Context context) {

    }
}

依赖

compileOnly 'com.ydl:m-user-api:0.0.3'

调用

UserService mUserService = ARouter.getInstance().navigation(UserService.class);
mUserService.getUser();

总结

本文中说明的方案在实践过程中调研了现有市面上流行的组件化架构,并在其基础上使用Gradle Plugin进行优化。降低项目业务组件之间的不必要的耦合依赖,节约接口层升级所带来的维护成本,并封装统一上传Task,避免了多次重复工作。

感谢以下极客的无私分享

斜杠Allen -- Android组件化框架设计与实践

上一篇 下一篇

猜你喜欢

热点阅读