使用 Annotation Processor 生成 Dagger 组件

Generate Dagger components using Annotation Processor

我正在开发一个遵循 MVP 架构模式的 Android 应用程序。在我所有的片段中,我都在注入一个 Presenter。因此,我的片段(视图)需要有一个组件,我在其中声明注入。例如:

@ActivityScope
@Component(
        dependencies = AppComponent.class,
        modules = {
                PresenterModule.class,
                InteractorModule.class
        }
)
public interface ViewInjectorComponent {
    void inject(SelectEventOccurrenceFragment fragment);
    void inject(CreateOpponentFragment fragment);
    void inject(SelectOpponentFragment fragment);
    void inject(TeammatesInvitedFragment fragment);
    ...
}

我添加到我的应用程序(片段)中的每个新视图都需要在此处声明其条目。我想知道是否可以使用某种注释处理器自动生成此代码。 App已经有好几个fragment了,这个component文件动辄300多条。如果我能做类似的事情那就太棒了:

@Injectable
public class MyNewFragment implements MyNewView {
...
}

然后在ViewInjectorComponent文件中自动生成入口。这是可能的?我应该看哪里?

您遇到的情况可能是您以不寻常的方式组织模块和组件的结果。特别是,横向分组(一个组件注入所有演示者)而不是垂直分组(一个组件注入与 SelectOpponentActivity 相关的功能)是有问题的。

Google Android Architecture Blueprints GitHub repo 是一个很好的例子。如果你仔细阅读那里的代码,你会发现他们在一个 Java 包中组织了与任务相关的功能以及一个单独的组件、模块、Presenter 等。这具有能够限制可访问性的好处类 的构造函数包含在其中并满足有效 Java 项目 13:最小化 类 和成员的可访问性。

同样,您已将所有模块组合到一个 Presenter 模块和一个 Interactor 模块中。 Dagger 2 官方文档中的建议是 organise Modules first for testability 然后沿着功能线。同样,您可以参考蓝图示例了解如何执行此操作。

最后,请注意,在使用大多数 DI 框架(如 Dagger 2)时不可避免地会涉及一些样板文件。从某种意义上说,您正在将一个更大的问题 ("how do I deal with all of these constructors?") 与更小且更易于管理的问题 ("how do I group my Components"等)。

更新 有一个名为 Auto Dagger2 的库可以为您生成组件。参见 this Github repo。这是注释的示例:

@AutoComponent
@Singleton
public class ExampleApplication extends Application { 
}

生成以下代码:

@Component
@Singleton
public interface ExampleApplicationComponent { 
}

如果您对代码生成工具感兴趣,另请查看 Google Auto

我不完全确定我要说的内容是否适合作为答案,但我会在这里碰碰运气。

即使你找到了一种方法来做你想做的事,也不要在生产中这样做(如果你只是想学习代码生成技术也没关系)。

您从这种方法中获得的好处很小(不是写几行琐碎的代码),但请考虑缺点:

  1. 代码生成逻辑需要written/debugged/maintained
  2. 这种做法将违反"principle of least astonishment"
  3. 代码生成很糟糕

请注意第三点——我是认真的。使用代码生成总是会导致维护开销,因此它应该只作为最后的手段使用。

Dagger 本身使用代码生成,但有一个很好的理由 - 性能。但是,性能在您的情况下不是问题。

总而言之:您的想法很有趣,但是像这样的方法不应该用于生产应用程序(除非这个功能被原生添加到 Dagger)。