请选择 进入手机版 | 继续访问电脑版

热点推荐

查看: 27|回复: 0

Android组件化神器 —— ServicePool

[复制链接]

该用户从未签到

20

主题

20

帖子

60

积分

注册会员

Rank: 2

积分
60
发表于 2020-2-14 16:35:39 | 显示全部楼层 |阅读模式
组件化开发过程中,随着组件越来越多,组件的之前的交互就会变得非常的复杂,此时组件间通信变得尤其的重要,ServicePool就是为组件化而生,用最简单的方式进行组件间通信。使用依赖注入,按需灵活注入组件。同时支持组件热插拔,达到组件即插即用的效果。可配置组件生命周期,做到组件按需创建和及时回收,充分利用懒加载的思想,有效解决组件初始化耗时导致的app启动速度问题。点击进入 项目地址
ServicePool包含有 Activity路由, 组件路由等等最常用的组件化能力。除此之外,组件化开发过程中有没有遇到过想使用某个已有的类,比如一个工具类的时候,发现这个工具类在当前类的上层,无法直接依赖和引用,而修改这个工具类的层级又会牵一发而动全身的问题? 有没有想要一个差异响应的能力,在不同的组件中或者环境下,有着不同的响应方式?有没有想要一个自适应场景的能力,自动适应当前环境(比如Java还是Android环境,比如Debug环境还是Release环境等等),从而使用最合适的功能。又有没有想过如何让组件做到像USB接口一样插上就能直接使用,拔掉也不影响主体功能的即插即用的效果。等等...。
下面就来具体介绍一下这个组件化神器——ServicePool!
ServicePool基础能力

如上图所示:

  • 组件A,B是两个互不依赖的组件,A,B不能直接通信
  • 组件A,B分别通过AService, BService对外提供服务
  • 组件A,B的接口协议存放在组件服务池pool, 分别是接口IA, IB
  • 当组件B需要组件A的服务时,组件B使用IA接口向ServicePool申请,
    由ServicePool创建并返回aService给组件B, 此时组件b可以使用aService的服务了
  • 同理, 组件A使用IB向ServicePool申请bService
  • aService,bService由ServicePool创建和管理
  • 所有Service对象的优先级生命周期可以通过@Service注解配置
/** * 服务池pool中 * * IA.java */public interface IA {    void aName();}/** * 服务池pool * * IB.java */public interface IB {    void bName();}/** * 组件A * * AService.java */@Servicepublic class AService implements IA {    @Override    public String aName() {        return "A Service";    }}/** * 组件B *  * BService.java */@Servicepublic class BService implements IB {    @Override    public String bName() {        return "B Service";    }}组件A中执行:   IB b = ServicePool.getService(IB.class);   System.out.println("I'm A Service, I can get " + b.bName());输出:   I'm A Service, I can get B Service组件B中执行:  IA a = ServicePool.getService(IA.class);  System.out.println("I'm B Service, I can get " + a.aName());输出:  I'm B Service, I can get A Service依赖注入(DI)

由于所有示例涉及到依赖注入,这里提前对ServicePool的依赖注入做个说明。和其他注入框架不同,ServicePool的注入方式很简单,只有一种注入方式就是直接通过Class注入。
@Servicepublic class AImpl implements IA {    @Override    public String aName() {        return "A Impl"    }}ServicePool就是一个基于Class注入容器。最后通过ServicePool.getService(IA.class)方法注入对象, 也可以通过@Service标记成员变量的方式注入,这两个方法等价。
public class MainActivity extends AppcompatActivity {    /**     * 等价于     * IA = ServicePool.getService(IA.class);     */    @Service    private IA a;         @Override    public void onCreate(Bundle savedInstanceState) {        System.out.println(a.getName()); //输出 A Service    }}ServicePool注入对象时,会根据Service配置的生命周期类型(scope)和优先级来决定当前是创建还是直接返回缓存对象。
指定Service优先级,按优先级顺序返回

如果IA有多个实现,如上图所示,ServicePool会比较每个实现优先级,来决定最终返回IA的哪个实现

  • @Service注解标记一个实现类时候可以通过参数priority指定这个实现类的优先级
  • 优先级值越大优先级越高, ServicePool默认会返回优先级最高的实现类对象
  • 如果多个实现类优先级相同,那么返回会有不确定性
  • 也可以直接指定具体使用哪个实现类,如ServicePool.getService(AService1.class)将会返回一个AService1对象
/** * 服务池pool中 *  * IPriorityService.java */public interface IPriorityService {    int getPriority();}/** * 组件A中 *  * PriorityService1.java * PriorityService2.java */@Service(priority = 1)public class PriorityService1 implements IPriorityService {    @Override    public int getPriority() {        return 1;    }}@Service(priority = 2)public class PriorityService2 implements IPriorityService {    @Override    public int getPriority() {        return 2;    }}组件B中执行:    IPriorityService priorityService = ServicePool.getService(IPriorityService.class);    System.out.println("priority is " + priorityService.getPriority());        priorityService = ServicePool.getService(PriorityService1.class);    System.out.println("priority is " + priorityService.getPriority());        priorityService = ServicePool.getService(PriorityService2.class);    System.out.println("priority is " + priorityService.getPriority());    输出:   priority is 2   priority is 1   priority is 2典型应用场景


  • Java Library组件和Android Library组件使用不同的服务, 如classloader等等。
  • debug环境,release环境或者不同的productFlavor使用不同的服务, 如logger,
    Mock等等
  • 不同的业务场景使用不同的服务
给服务对象指定生命周期

每个由ServicePool创建的service对象都有各自生命周期,service对象的生命周期由ServicePool管理,
并由@Service注解配置生命周期类型。

  • Service有once, temp, global三种生命周期类型.
  • 指定Service的生命周期为once,@Service(scope=IService.Scope.once),每次ServicePool.getService()都会创建一个新的对象,对象使用后随gc自动被回收,
    scope默认为once
  • 指定Service的生命周期为temp,@Service(scope=IService.Scope.temp),Service由WeakReference缓存,只适用无状态服务。
  • 指定Service的生命周期为global,@Service(scope=IService.Scope.global),每次ServicePool.getService()拿到的都是同一个对象,App运行期间不会被回收
组件A中/** *  * OnceService.java */@Service(scope = IService.Scope.once)public class OnceService implements LifecycleService {}/** *  * TempService.java */@Service(scope = IService.Scope.temp)public class TempService implements LifecycleService {}/** *  * GlobalService.java */@Service(scope = IService.Scope.global)public class GlobalService implements LifecycleService {}组件B中执行:    System.out.println(ServicePool.getService(OnceService.class) == ServicePool.getService(OnceService.class));    //System.out.println(ServicePool.getService(TempService.class) == ServicePool.getService(TempService.class));//不可靠    System.out.println(ServicePool.getService(GlobalService.class) == ServicePool.getService(GlobalService.class));输出:    false    true支持通过path查找Service

由于ServicePool是基于class做的注入操作, ServicePool内部会将path映射成Class,这个映射操作是在编译期完成的。




/** * 服务池pool中 *  * IPathService.java */public interface IPathService {    String pathServiceName();}/** * 组件A中 *  * PathService */@Service(path = "pathService")public class PathService implements IPathService {    @Override    public String pathServiceName() {        return "Path Service";    }}IPathService是任意定义的接口,它可以有一个或多个实现类,只要在实现类上加@Service注解并指定path属性。我们就可以通过ServicePool.getService(path)来找到或者创建他的实现类对象。
组件B中执行:    IPathService pathService = ServicePool.getService("pathService");    System.out.println(pathService.pathServiceName());输出:    Path Service典型应用场景:


  • activity路由
  • 混合开发中,可以通过path将桥接方法分发到对应执行器
组件初始化

app开发过程中,肯定少不了对组件进行初始化,无论是内部组件还是引用外部库,很多都需要执行初始化操作。常规的方式是所有初始化操作都是放到Application的onCreate()/onAttachBaseContext()方法中执行。组件有很多而Application只有1个, 如何让每个组件都可以拥有它自己的初始化类呢?
ServciePool中有一个@Init注解,任何被@Init注解标记的Service类被认为是一个需要执行操作初始化操作的Service类, 同时这个Service类需要实现IInitService接口。
@Init(lazy = false) //lazy = false表示禁用懒加载,则该Service会随Application初始化而初始化@Servicepublic class InitService implements IInitService {        @Override    public void onInit() {        //do something.    }}如果初始化组件想要随Application初始化而初始化,需要将@Init注解的lazy赋值为false,表示禁用懒加载。
除了lazy属性,@Init注解还有async,dependencies两个属性。
async属性顾名思义是异步执行,async默认为false,设置为true表示该组件初始化会在异步线程执行。
dependencies可以传递一个初始化组件类数组,表示当前组件初始化依赖这个数组中的所有组件。ServicePool会先初始化数组中的组件再去执行当前组件的初始化。
@Init@Servicepublic class InitService1 implements IInitService {        @Override    public void onInit() {        System.out.println("Service 1 Inited!!!");    }}@Init@Servicepublic class InitService2 implements IInitService {        @Override    public void onInit() {        System.out.println("Service 2 Inited!!!");    }}@Init(lazy = false, dependencies=[InitService1.class, InitService2.class])@Servicepublic class InitService3 implements IInitService {        @Override    public void onInit() {        System.out.println("Service 3 Inited!!!");    }}由于InitService1, InitService2之间没有依赖关系,因此他两的执行顺序不确定,InitService3同时依赖InitService1和InitService2,因此InitService3一定是最后执行的。
Application初始化后执行结果:    Service 2 Inited!!!    Service 1 Inited!!!    Service 3 Inited!!!ServicePool的初始化在如何优雅的管理多环境下的Android代码这篇文章的最后中有实际应用,也可做为示例参考。
组件懒加载机制 & 禁用懒加载

所有初始化操作都随Application启动执行,一方面会导致Application非常臃肿,另一方面虽然单个组件初始化时长很短,但n多个组件初始化时长结合在了一起就会导致启动时间超长。
懒加载是ServicePool的核心思想。所有组件只有在第一次被使用时才会被创建和执行初始化。而不是集中在Application初始化过程。分散初始化从而减轻App启动压力。举个
微信分享是很常用的功能,我们以微信分享为例,WXShareManager用来助力微信分享相关操作。
@Init@Servicepublic class WXShareManager implement IInitService {        public static final String appId = "wx499fa9b1ba4a93db";    public static final String userName = "gh_6619a14a139d";    @Override    public void onInit() {        IWXAPI wxApi = WXAPIFactory.createWXAPI(mContext, null);        wxApi.registerApp(appId);    }        public void share(...) {        //do wx share.    }}shareManager注入对象的时候初始化操作会被执行。
public class ShareActivity extends AppcompatActivity {    @Service    private WXShareManager shareManager;//此时会触发WXShareManager的onInit初始化。        ...        void onClick(View v) {        shareManager.share(...);    }}组件热插拔

未完待续....
Activity路由

未完待续....
快速接入ServicePool

Java吧 收集整理 java8论坛 www.java8.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表