【问题标题】:What are the advantages of using DispatchingAndroidInjector<> and the other dagger.android classes?使用 DispatchingAndroidInjector<> 和其他 dagger.android 类有什么好处?
【发布时间】:2017-06-15 18:10:42
【问题描述】:

我正在将 Dagger 2 设置到我的 android 项目中。这是我第一次使用这个框架,到目前为止一切顺利。但是我看到了在项目中设置这个框架的不同方法,我想知道哪个更好,因为我比较了两者,对我来说结果是一样的。

我遵循了这个指南:https://github.com/codepath/android_guides/wiki/Dependency-Injection-with-Dagger-2

在互联网上搜索他们都使用这种方法。 它使用@Module 和@Component 来定义依赖关系。

你的应用程序最终是这样的:

public class MyApp extends Application {

    private NetComponent mNetComponent;

    @Override
    public void onCreate() {
        super.onCreate();

        // Dagger%COMPONENT_NAME%
        mNetComponent = DaggerNetComponent.builder()
                // list of modules that are part of this component need to be created here too
                .appModule(new AppModule(this)) // This also corresponds to the name of your module: %component_name%Module
                .netModule(new NetModule("https://api.github.com"))
                .build();

        // If a Dagger 2 component does not have any constructor arguments for any of its modules,
        // then we can use .create() as a shortcut instead:
        //  mNetComponent = com.codepath.dagger.components.DaggerNetComponent.create();
    }

    public NetComponent getNetComponent() {
       return mNetComponent;
    }
}

但是我找到了另一种方法(我没有测试过):https://google.github.io/dagger/android.html 它看起来完全不同,使用不同的类和注释。 它使用这样的东西:

@Subcomponent(modules = ...)
 public interface YourActivitySubcomponent extends AndroidInjector<YourActivity> {
   @Subcomponent.Builder
   public abstract class Builder extends AndroidInjector.Builder<YourActivity> {}
 }

@Module(subcomponents = YourActivitySubcomponent.class)
 abstract class YourActivityModule {
   @Binds
   @IntoMap
   @ActivityKey(YourActivity.class)
   abstract AndroidInjector.Factory<? extends Activity>
       bindYourActivityInjectorFactory(YourActivitySubcomponent.Builder builder);
 }

 @Component(modules = {..., YourActivityModule.class})
 interface YourApplicationComponent {}

public class YourApplication extends Application implements HasDispatchingActivityInjector {
   @Inject DispatchingAndroidInjector<Activity> dispatchingActivityInjector;

   @Override
   public void onCreate() {
     super.onCreate();
     DaggerYourApplicationComponent.create()
         .inject(this);
   }

   @Override
   public DispatchingAndroidInjector<Activity> activityInjector() {
     return dispatchingActivityInjector;
   }
 }

所以,我的问题是:

  1. 哪个更好?

  2. 选择一种方法而不是另一种方法的原因是什么?

【问题讨论】:

  • 你能详细说明有什么不同吗?
  • 另外,看看这个github.com/googlesamples/android-architecture/tree/… 通常我会遵循谷歌推荐的任何内容。他们维护 Dagger 2 :D
  • 我附上了代码中的主要区别,以便更好地了解我在说什么!!
  • @Shmuel 您提供的示例回购代码与我编写的相同。但是这个链接 (google.github.io/dagger/android.html) 显示的是不同的东西。如您所见,该网址也来自谷歌=P。也许我错过了什么。
  • 你会发现 Dagger 的十几种不同的实现方式,复杂程度不一。最后一个示例看起来像是生成注入过程并使用子组件 - 老实说,我尝试使用 KISS 原则。考虑到这两个中的哪一个将适合您的目的,同时实现相同的目标。对我来说,DI 应该用这个库解决的令人头疼的问题正在被它越来越复杂的实现所抵消。

标签: android dagger-2


【解决方案1】:

现在官方Dagger 2 documentation 中规定的为 Android 设置 Dagger 2 的方法有很多优点,应该是首选。优点只是那里阐述的那些,即:

  1. 复制粘贴代码使以后难以重构。随着越来越多的开发者复制粘贴该块,越来越少的人会知道它实际上做了什么。

  2. 更根本的是,它需要请求注入的类型 (FrombulationActivity) 知道它的注入器。即使这是通过接口而不是具体类型完成的,它也打破了依赖注入的核心原则:一个类不应该知道它是如何被注入的。

让我们将这些理由应用到您的第一个示例中。

原因 1

假设我们有一个 Activity 想要使用您的 NetComponent。我们称之为NetActivityNetActivityonCreate(Bundle savedInstanceState) 方法看起来像这样:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ((MyApp) getApplicationContext()).getNetComponent().inject(this);
}

此代码具有分散在燕麦片上的脚趾甲剪报的所有视觉吸引力(不是我的明喻),最终将复制粘贴到您使用 NetComponent 的所有注射部位活动中。如果您使用更复杂的组件,例如文档中的这个示例:

@Override
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  // DO THIS FIRST. Otherwise frombulator might be null!
  ((SomeApplicationBaseType) getContext().getApplicationContext())
     .getApplicationComponent()
     .newActivityComponentBuilder()
     .activity(this)
     .build()
     .inject(this);
 // ... now you can write the exciting code

}

更糟糕的是。它很容易退化为一段神奇的代码,必须在整个注入点复制和粘贴。如果它发生变化,很容易忘记只更新一个站点并导致您的应用崩溃。

原因 2

依赖注入的一大优点是注入站点不需要知道或关心它们的注入器,就像依赖项不知道或关心它们的依赖项一样。要返回我们的NetActivity,我们有:

((MyApp) getApplicationContext()).getNetComponent().inject(this);

Activity“知道”它的注入器 (NetComponent),并且 Activity 现在与混凝土 MyApp 和来自相同的方法 getNetComponent() 耦合。如果这些类中的任何一个发生更改,NetActivity 也必须更改。

遵循 Dagger 2.10 及更高版本中可用的 Activity 和 Fragments 中的新注入方式的优点与这些缺点正好相反:

  1. 您最终会得到更少的复制粘贴代码
  2. 请求注入的类型不再需要知道或关心他们的注入器或注入器的来源。

此外,正如 this blog 中所指出的,优先使用子组件而不是依赖组件会减少应用的方法数。

虽然使用子组件最初可能看起来更困难,但有一些明显的优势。但是,出于学习 Dagger 依赖组件的目的,最初可能更容易理解。如果第二个示例一开始太复杂,您可以在熟练后逐步使用首选方法。

【讨论】:

  • 嗨,大卫。我看到了页面中描述的这些优势。尽管第二个优势是有道理的,但第一个优势却没有:“复制粘贴代码使以后难以重构。随着越来越多的开发人员复制粘贴该块,很少有人会知道它实际上做了什么。”您最终会更改此代码“((MyApp) getApplication()).getNetComponent().inject(this);”对于这个“AndroidInjection.inject(this);”所以无论如何你都必须粘贴代码。
  • @LeandroOcampo 你是对的,仍然会有一些复制/粘贴。但是对于第二种方法,并没有那么多。无论如何感谢您的接受
  • 我认为不同之处在于人们可能可以推断出AndroidInjection.inject(this) 做了什么,因为它保持简单。在前一个示例中,以及文档中的// DO THIS FIRST 示例中,它要复杂得多,并且需要更多地了解该代码的作用。当事情像那样复杂时,这意味着复制/粘贴它的人可能甚至不会努力去理解它,他们只是复制它,因为它是“你应该做的”。 Injector.inject(this);super.onCreate() 一样容易理解,我们都已经毫无疑问地这样做了。
  • @Joe 说得好。你想把它变成答案吗?
猜你喜欢
  • 1970-01-01
  • 2010-10-02
  • 1970-01-01
  • 1970-01-01
  • 2012-06-02
  • 1970-01-01
  • 1970-01-01
  • 2019-07-16
相关资源
最近更新 更多