如果你对本文感兴趣,也许你对我的公众号也会有兴趣,可扫下方二维码或搜索公众微信号:mxszgg
前言
如果读者对模块化开发的服务调用具有一定的认识可以跳过下面一小节。
模块化开发中的服务调用概念
模块化开发现在对于 Android 开发者来说应该是一个耳熟能详的名词了,现在应该有许多应用的开发迭代都使用了模块化开发,模块化开发的意义是在于将 App 的业务细分成 N 个模块,利于开发人员的协作开发。模块化开发当中有一个需要解决的问题就是模块之间的服务调用——因为各个模块是以 library 形式存在,彼此之间不相互依赖,故使彼此之间实际上并不知道对方的存在,那么当 A 模块想要知道 B 模块中的某个信息,需要调用 B 中的某个方法时该怎么办呢?例如开发人员当前正在 main 模块开发,当前的一个 TextView 需要展示电影信息,但是很明显电影信息这块属于 movie 模块而并不是 main 模块,那么此时该如何解决呢?机智的 Android 开发人员创建了基础模块 service 并让所有的业务模块依赖 service 模块,service 模块的职责也很简单,只需要提供接口声明,具体的实现就交给具体的业务模块自己去实现了。例如 service 模块中提供一个 MovieService 类:
public interface MovieService {
String movieName();
}
那么在 movie 模块中就可以创建一个 MovieServiceImpl 类去实现 MovieService 接口了——
public class MovieServiceImpl implements MovieService {
@Override public String movieName() {
return "一出好戏";
}
}
而对于 main 模块来说,它应该调用 MovieService 实现类的 movieName()
方法就好了,但是事实上 main 模块又不可能知道 MovieService 的具体实现类是什么,所以看起来似乎问题又卡住了…
解决方案
实际上问题在于如何获取到接口实现类的路径,例如 renxuelong/ComponentDemo 中所提到的,反射调用所有模块的 application 的某个方法,在该方法中将接口与实现类映射起来,该方法的弊端很明显,开发者需要显示填写所有模块 application 的完全限定名,这在开发中应当是尽量避免的。
流行的解决方案就是 ARouter 的实现方式了——使用 APT—— build 时扫描所有的被 @Route
注解所修饰的类,判断该类是否实现了某个接口,如果是的话则创建相应的 xxx$$app
类,读者可以下载 ARouter 的 demo 在 build 之后找到 ARouter$$Providers$$app
类 ——
如上图所示,左侧是接口的完全限定名,右侧是具体的实现类,这样就将接口与实现类一一映射起来了,相比于上面所提到的方法,开发者并不需要手动地去填写类的完全限定名,因为在实际开发中类的路径是很可能被改变的,这种撰写类的完全限定名的操作应该避免由开发者去做,而应该去交给构建工具去完成。
实际上笔者本文所想要阐述的方案与 APT 的原理是一样的,通过扫描指定注解所修饰的类获取到所有的 service 接口的实现类,并用 Map 将其维护起来。
Transform API
结合官方文档文档上来说,Transform 是一个类,构建工具中自带诸如 ProGuardTransform
、DexTransform
等 Transfor