项目地址:github.com/johnsonlee/…html
作 Java 开发的同窗应该对 SPI (Service Provider Interface) 不会陌生,不管是 JDK、Gradle 亦或是一些第三方框架,都或多或少的用它来实现可扩展的能力,为何在 Android 平台上却不为人知呢?java
我的认为缘由有 2 点:android
Android 与 Java 应用的分发方式不一样git
Java 应用采用 JAR 分发,扩展起来很是容易,而 Android APK 一旦打好包,就至关于固化下来了,实现可扩展须要借助于其它非官方推荐的手段github
SPI 在 Android 平台上的性能堪忧编程
因为 Android 设备的性能广泛低于 PC ,加上 Android 平台特有的 ANR 机制,使得 SPI 很容易在 Android 上发生 卡顿甚至 ANRmarkdown
Java 官方的定义是:架构
提供访问特定应用功能和特性的一系列编程接口和类oracle
由 Service 定义的一系列公共接口和抽象类框架
SPI 的实现
Java 原生的 SPI 是经过 ClassLoader 在 CLASSPATH 中搜索 META-INF/services/ 下 SPI 配置文件,而后读取配置文件中的内容,因此须要解析 JAR 文件(Android 平台是解析 APK),而这个过程须要遍历整个 JAR/APK 中全部的条目,所以很是耗时(当年就被它坑得很惨)
既然 SPI 在 Android 上表现这么差,为何还要用它呢?
在应用开发的过程当中,不免由于应用架构的缘由,须要支持非运行时可扩展能力,好比:接口与实现分离、一个接口对应多个实现须要动态查找、反向依赖等等,相对于 Dagger 来讲,它简单、原生 API 支持、不须要依赖额外的第三方库。
既然选择了 SPI,如何解决 SPI 在 Android 平台上的性能瓶颈?——去 I/O
方法其实也很简单,分为以下几个步骤,咱们不妨用逆向思惟来看:
可是这里有几个问题:
能够是 Class 的映射,可是,若是要实例化 Service Provider 就得须要反射
固然是能够的,这样 ServiceRegistry 中存储的映射关系就须要调整为 Class<Service> 与 Creator<ServiceProvider> 之间的映射关系,内容大体以下:
public class ServiceRegistry { static final Map<Class<?>, List<Callable<?>>> registry = new HashMap<>(); } 复制代码
Creator 的内容大体以下:
public class ServiceProviderCreator implements Callable<ServiceProvider> { @Override public ServiceProvider call() { return new ServiceProvider(); } } 复制代码
public class ServiceRegistry { static final Map<Class<?>, List<Callable<?>>> registry = new HashMap<>(); static { register(InterfaceA.class, new InterfaceACreator()) } } 复制代码
该方案已经彻底开源,项目地址:github.com/johnsonlee/… star 和 PR。