Android中的编译时依赖注入权衡

作为后端软件开发人员,我习惯于使用Spring作为我最喜欢的依赖注入引擎。 替代方案包括Java EE的CDI ,它以不同的方式获得相同的结果。 但是,两者都在运行时注入:这意味着在应用程序启动时(要满足所有依赖关系所需的时间)要付出一定的性能成本。 在应用程序服务器上,以天数(如果不是几周)来衡量应用程序寿命,则可以接受启动时间开销。 如果服务器只是大型群集中的一个节点,则甚至完全透明。

作为Android用户,我对启动应用程序感到不满意,并且在打开之前它会滞后几秒钟。 如果我们再增加几秒钟的时间,那么对用户友好性将是非常糟糕的。 更糟糕的是,DI引擎的内存消耗将是一场灾难。 这就是Square开发出一种称为Dagger的编译时依赖注入机制的原因。 请注意,Google目前正在开发Dagger 2 。 在继续之前,我必须承认Dagger 2的文档简明扼要-充其量。 但这是另一篇博客文章的绝佳机会:-)

Dagger 2与注释处理器一起使用:编译时,它将分析您的注释代码并在您的组件之间生成接线代码。 好处是该代码与手动编写的代码非常相似,没有秘密的黑魔法(与运行时DI及其代理相对)。 以下代码显示要注入的类:

publicclassTimeSetListenerimplementsTimePickerDialog.OnTimeSetListener{

    privatefinalEventBuseventBus;

    publicTimeSetListener(EventBuseventBus){
        this.eventBus=eventBus;
    }

    @Override
    publicvoidonTimeSet(TimePickerview,inthourOfDay,intminute){
        eventBus.post(newTimeSetEvent(hourOfDay,minute));
    }
}

注意,代码在各个方面都完全独立于Dagger。 人们无法推断出最终将如何注入它。 有趣的部分是如何使用Dagger注入所需的eventBus依赖项。 分两个步骤:

1.在上下文中获取对eventBus实例的引用1.使用相关参数调用构造函数

接线配置本身是在所谓的模块中完成的:

@Module

publicclassApplicationModule{

    @Provides
    @Singleton
    publicTimeSetListenertimeSetListener(EventBuseventBus){
        returnnewTimeSetListener(eventBus());
    }

    ...
}

请注意, EventBus作为参数传递给方法,由提供它的上下文决定。 同样,作用域是@Singleton

与工厂的绑定发生在一个组件中 ,该组件引用了所需的模块(或更多模块):

@Component(modules=ApplicationModule.class)
@Singleton
publicinterfaceApplicationComponent{

    TimeSetListenertimeListener();

    ...
}

这是非常简单的...直到有人注意到Android中的某些对象(如果不是大多数)具有由Android本身管理的生命周期,而无需调用我们的注入友好构造函数 。 活动就是这样的对象:它们是由框架实例化和启动的。 只有通过像onCreate()这样的专用生命周期方法,我们才能将代码连接到对象中。 由于必须进行电场注入,因此该用例看起来要糟糕得多。 更糟糕的是,还需要调用Dagger:在这种情况下,它充当普通工厂。

publicclassEditTaskActivityextendsAbstractTaskActivity{

    @InjectTimeSetListenertimeListener;
    @Override
    protectedvoidonCreate(BundlesavedInstanceState){
        DaggerApplicationComponent.create().inject(this);
    }

    ...
}

我们第一次看到与Dagger的耦合,但这是一个很大的耦合。 什么是DaggerApplicationComponent ? 前一个ApplicationComponent的实现,以及提供它们实例的工厂。 而且由于它不提供inject()方法,因此我们必须在接口中声明它:

@Component(modules=ApplicationModule.class)
@Singleton

publicinterfaceApplicationComponent{

    TimeSetListenertimeListener();

    voidinject(EditTaskActivityeditTaskActivity);

    ...
}

作为记录,生成的类如下所示:

@Generated("dagger.internal.codegen.ComponentProcessor")
publicfinalclassDaggerApplicationComponentimplementsApplicationComponent{

  privateProvider<TimeSetListener>timeSetListenerProvider;
  privateMembersInjector<EditTaskActivity>editTaskActivityMembersInjector;

  ...

  privateDaggerApplicationComponent(Builderbuilder){
    assertbuilder!=null;
    initialize(builder);
  }

  publicstaticBuilderbuilder(){
    returnnewBuilder();
  }

  publicstaticApplicationComponentcreate(){
    returnbuilder().build();
  }

  privatevoidinitialize(finalBuilderbuilder){
    this.timeSetListenerProvider=ScopedProvider.create(ApplicationModule_TimeSetListenerFactory
        .create(builder.applicationModule,eventBusProvider));
    this.editTaskActivityMembersInjector=TimeSetListener_MembersInjector
        .create((MembersInjector)MembersInjectors.noOp(),timeSetListenerProvider);
  }

  @Override
  publicEventBuseventBus(){
    returneventBusProvider.get();
  }

  @Override
  publicvoidinject(EditTaskActivityeditTaskActivity){
    editTaskActivityMembersInjector.injectMembers(editTaskActivity);
  }

  publicstaticfinalclassBuilder{

    privateApplicationModuleapplicationModule;

    privateBuilder(){}

    publicApplicationComponentbuild(){
      if(applicationModule==null){
        this.applicationModule=newApplicationModule();
      }
      returnnewDaggerApplicationComponent(this);
    }

    publicBuilderapplicationModule(ApplicationModuleapplicationModule){
      if(applicationModule==null){
        thrownewNullPointerException("applicationModule");
      }

      this.applicationModule=applicationModule;
      returnthis;
    }
  }
}

没有免费的午餐。 乍看之下,尽管编译时DI非常吸引人,但在生命周期不受我们的代码管理的对象上使用时,它的影响要小得多。 缺点显而易见:耦合到DI框架,更重要的是增加了对单元进行单元测试的难度。 但是,考虑到Android的限制,这可能是最好的选择。

翻译自: https://blog.frankel.ch/compile-time-dependency-injection-tradeoffs-in-android/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值