简体   繁体   English

基于构建类型和风格的更好的 Dagger 依赖注入?

[英]Better Dagger dependency injection based on build type and flavor?

I am using aproach to provide modules to Dagger described in answer of this question Android Customize Workflow for Product Flavors我正在使用 aproach 为 Dagger 提供模块,在这个问题的回答中描述了Android Customize Workflow for Product Flavors

Our approach is a bit different - we have Modules in debug build type in src/debug/java and in release build type in src/release/java .我们的方法有点不同 - 我们在src/debug/java中有debug构建类型的Modules ,在src/release/java中有release构建类型。 Our main module is called ApplicationModule it includes all other.我们的主模块称为ApplicationModule它包括所有其他模块。

Modules in src/debug/java provides some custom behaviour for debugging, logging etc and overrides ApplcationModule . src/debug/java Modules为调试、日志记录等提供了一些自定义行为,并覆盖了ApplcationModule

Now we have a need to have custom behaviour based on application flavor.现在我们需要有基于应用程序风格的自定义行为。

What would be correct approach to do that?这样做的正确方法是什么?

For example flavors A to C should provide custom behaviours, while flavors D to F should provide basic, default behaviour.例如,口味 A 到 C 应该提供自定义行为,而口味 D 到 F 应该提供基本的默认行为。

So far I came up with such.到目前为止,我想出了这样的。

  • All flavors (not build types) has same class in src/flavorX/java/com.application.FlavorModule所有风格(不是构建类型)在src/flavorX/java/com.application.FlavorModule都有相同的类
  • To avoid code duplication only flavors A to C provide custom behavior while other completely empty so that project would compile.为了避免代码重复,只有风格 A 到 C 提供自定义行为,而其他完全空,以便项目可以编译。 And default behaviour is provided my module in src/main/java并且在src/main/java提供了我的模块的默认行为

Is there a better way to achieve such result?有没有更好的方法来实现这样的结果? Because I don't like empty src/flavorX/java/com.application.FlavorModule and don't like code duplication...因为我不喜欢空的src/flavorX/java/com.application.FlavorModule也不喜欢代码重复......

Little complicated but here's how I did it:有点复杂,但我是这样做的:

Create an interface MainComponent and keep it in src/main, this should contain anything that is not flavor specific创建一个接口 MainComponent 并将其保存在 src/main 中,这应该包含任何非特定于风味的内容

public interface MainComponent {
    void inject(MyApplication o);

    void inject(BusinessObject o);

    Foo getFoo();

    Activitycomponent plusActivityComponent(ActivityModule activityModule);

} }

Within each flavor create an interface that inherits from the above one在每种风格中创建一个继承自上述风格的接口

public interface FlavorComponent extends MainComponent {
//flavor specific injection stuff similar to SourceComponent
}

Within Debug/Beta/Release create the actual component and extend the FlavorComponent (giving you all the flavor specific niceties).在 Debug/Beta/Release 中创建实际组件并扩展 FlavorComponent(为您提供所有特定于风味的细节)。

@Singleton
 @Component(modules = {ApplicationModule.class, FlavorModule.class,
         BetaApplicationModule.class, AnotherModuleJustBecause.class})
public interface ApplicationComponent extends FlavorComponent {
     void inject(NYTApplication a);

 }

Notice that you can also include a flavor specific FlavorModule that can be different in each flavor or not include it in Release while including it in Beta.请注意,您还可以包含特定于风味的 FlavorModule,它可以在每种风味中不同,或者不包含在 Release 中,而将其包含在 Beta 中。

Also include a ComponentFactory within Debug/Beta/Release returning the common Flavor Component Interface还在 Debug/Beta/Release 中包含一个 ComponentFactory 返回通用的 Flavor 组件接口

public class ComponentFactory {

public static final FlavorComponent getComponent(Application context) {
        return DaggerApplicationComponent.builder()
                .applicationModule(new ApplicationModule(context))
                .build();
    }

and finally from your Application class call:最后从您的应用程序类调用:

ComponentFactory.getComponent(this).inject(this);

The component factory will return the Build Type Component which will extend the Flavor's Component.组件工厂将返回构建类型组件,它将扩展 Flavor 的组件。

My solution was an adaptation of this article cited above我的解决方案是改编上面引用的这篇文章

I have an interface call ApplicationComponent in src/main:我在 src/main 中有一个接口调用 ApplicationComponent:

    @Singleton
    @Component(modules = [

        FlavorModule::class,

        Anyothermoduleyouhave::class

    ])

    interface ApplicationComponent {}

Now, inside of each flavor folder, you have to create 2 files:现在,在每个风味文件夹中,您必须创建 2 个文件:

  1. FlavorModule (an abstracted class to call your config) FlavorModule(一个抽象类来调用你的配置)
  2. FlavorConfig (the config or whatever specific flavor code you need) FlavorConfig(配置或您需要的任何特定风味代码)

by the way: if you don't have any source folder you can create by adding on your gradle file:顺便说一句:如果您没有任何源文件夹,您可以通过添加您的 gradle 文件来创建:

        java.srcDirs += ['src/main/kotlin', 'src/myFlavorCode/kotlin']

and creating the kotlin folder as well并创建 kotlin 文件夹

FlavorModule:风味模块:

    @Module
    class FlavorModule {

        @[Provides Singleton]
        fun getConfig(config: MySpecificFlavor1Config): FlavorConfig

    }

FlavorConfig风味配置

    class MySpecificFlavor1Config @Inject constructor() : FlavorConfig {
        override fun getMyValueThatImLookingFor() = "flavor 1 woooooow"
    }

Do the same for the Flavor 2对 Flavor 2 做同样的事情

Important: to make this work dynamically with dagger, use the same package path for both FlavorModule/FlavorConfig classes, like package br.com.main.config, this way dagger understands which FlavorModule to use重要提示:为了使用 dagger 动态地工作,对 FlavorModule/FlavorConfig 类使用相同的包路径,比如包 br.com.main.config,这样 dagger 就知道要使用哪个 FlavorModule

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM