Dagger2 User's Guide(全文翻译--中英)

Dagger 2 是一款高效的依赖注入框架,简化了 Android 和 Java 应用的依赖管理。通过代码生成机制,Dagger 2 提供了一种简洁的方式声明依赖关系,减少了样板代码,提升了开发效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Dagger User’s Guide(Dagger用户指南)

The best classes in any application are the ones that do stuff: the BarcodeDecoder, the KoopaPhysicsEngine, and the AudioStreamer. These classes have dependencies; perhaps a BarcodeCameraFinder, DefaultPhysicsEngine, and an HttpStreamer.

任何应用程序中最好的类都是做一些事情的类:BarcodeDecoder,  KoopaPhysicsEngine, and  AudioStreamer. 这些类有依赖性;可能是BarcodeCameraFinder、DefaultPhysicsEngine和HttpStreamer。

 

To contrast, the worst classes in any application are the ones that take up space without doing much at all: the BarcodeDecoderFactory, the CameraServiceLoader, and the MutableContextWrapper. These classes are the clumsy duct tape that wires the interesting stuff together.

相比之下,任何应用程序中最糟糕的类是那些占用空间却不做太多事情的类:the BarcodeDecoderFactory, the CameraServiceLoader, and the MutableContextWrapper. 这些类时笨拙的胶带把有趣的类连接在一起。

Dagger is a replacement for these FactoryFactory classes that implements the dependency injection design pattern without the burden of writing the boilerplate. It allows you to focus on the interesting classes. Declare dependencies, specify how to satisfy them, and ship your app.

Dagger是这些工厂类的替代品,它实现了依赖注入设计模式,没有了编写样本工厂的负担。Dagger让你聚焦于真正做事情的类(interesting classes) 。声明依赖项,指定如何满足它们,然后发布应用程序。

By building on standard javax.inject annotations (JSR 330), each class is easy to test.You don’t need a bunch of boilerplate just to swap the RpcCreditCardService out for a FakeCreditCardService.

 

Dagger建立在java依赖注入标准(JSR330)上,每个类都很容易测试。您不需要一堆样本文件来将RpcCreditCardService交换为FakeCreditCardService指 关系转换简单?.

Dependency injection isn’t just for testing. It also makes it easy to create reusable, interchangeable modules. You can share the same AuthenticationModule across all of your apps. And you can run DevLoggingModule during development and ProdLoggingModule in production to get the right behavior in each situation.

依赖注入不仅仅用于测试。它还可以很容易地创建可重用的、可互换的模块。您可以在所有的应用程序中共享相同的AuthenticationModule。您可以在开发过程中运行DevLoggingModule,在产品中运行ProdLoggingModule,以获得每种情况下的正确行为。

 

Why Dagger 2 is Different(为什么Dagger2是与众不同的)

Dependency injection frameworks have existed for years with a whole variety of APIs for configuring and injecting. So, why reinvent the wheel? Dagger 2 is the first to implement the full stack with generated code. The guiding principle is to generate code that mimics the code that a user might have hand-written to ensure that dependency injection is as simple, traceable and performant as it can be. For more background on the design, watch this talk (slides) by +Gregory Kick.

依赖关系注入框架已经存在了很多年,具有用于配置和注入的各种api。那么,为什么要重新发明轮子呢?Dagger2是第一个用生成的代码实现完整堆栈的。指导原则是生成代码尽量模拟用户可能手工编写的代码,以确保依赖注入尽可能简单、可跟踪和性能。要了解更多的设计背景,请观看+Gregory Kick的演讲(幻灯片)(ps:链接 https://plus.google.com/+GregoryKick/)。

 

 

Using Dagger(使用Dagger)

We’ll demonstrate dependency injection and Dagger by building a coffee maker. For complete sample code that you can compile and run, see Dagger’s coffee example.

我们将通过建立一个咖啡机来演示依赖注入和Dagger。您可以编译和运行的完整的示例代码,参见Dagger的咖啡示例(ps:链接 https://github.com/google/dagger/tree/master/examples/simple/src/main/java/coffee)。

 

Declaring Dependencies声明依赖

Dagger constructs instances of your application classes and satisfies their dependencies. It uses the javax.inject.Inject annotation to identify which constructors and fields it is interested in.

Use @Inject to annotate the constructor that Dagger should use to create instances of a class. When a new instance is requested, Dagger will obtain the required parameters values and invoke this constructor.

Dagger构建应用程序类的实例并满足它们的依赖关系。它使用javax.inject.Inject注解来识别哪些构造函数和字段是感兴趣的。

使用@Inject来标注Dagger应该用来创建类实例的构造函数。当需要一个新的实例时,Dagger会获得所需的参数值并调用这个构造函数。

 

 

class Thermosiphon implements Pump {

  private final Heater heater;

 

  @Inject

  Thermosiphon(Heater heater) {

    this.heater = heater;

  }

 

  ...}

 

Dagger can inject fields directly. In this example it obtains a Heater instance for the heater field and a Pump instance for the pump field.

 

Dagger可以直接注入字段。在这个例子中,它获得了一个Heater类的实例应用于heater字段和一个Pump类的实例应用于pump字段

 

class CoffeeMaker {

  @Inject Heater heater;

  @Inject Pump pump;

 

  ...}

 

If your class has @Inject-annotated fields but no @Inject-annotated constructor, Dagger will inject those fields if requested, but will not create new instances. Add a no-argument constructor with the @Inject annotation to indicate that Dagger may create instances as well.

Dagger also supports method injection, though constructor or field injection are typically preferred.

Classes that lack @Inject annotations cannot be constructed by Dagger.

如果你的类有@Inject注释的字段,但没有@Inject注释的构造方法,那么Dagger将会在需要的时候注入这些字段,但不会创建新的实例。用@Inject注释添加一个无参数的构造函数来说明Dagger也可以创建实例。

 

Dagger还支持方法注入,尽管构造函数或字段注入通常是首选。

 

缺少@Inject注释的类不能用Dagger来构造。

 

Satisfying Dependencies满足依赖

By default, Dagger satisfies each dependency by constructing an instance of the requested type as described above. When you request a CoffeeMaker, it’ll obtain one by calling new CoffeeMaker() and setting its injectable fields.

For example, provideHeater() is invoked whenever a Heater is required:

 

默认情况下,Dagger通过构造如上所述请求类型的实例来满足每个依赖项。当你请求一个CoffeeMaker时,它会通过调用new CoffeeMaker()来获得一个,并设置它的可注入的字段。

 

But @Inject doesn’t work everywhere:

  • Interfaces can’t be constructed.
  • Third-party classes can’t be annotated.
  • Configurable objects must be configured!

For these cases where @Inject is insufficient or awkward, use an @Provides-annotated method to satisfy a dependency. The method’s return type defines which dependency it satisfies.

 

但是@Inject不是在任何地方都能用的:

 

#接口不能构造。

#第三方类不能注释。

#可配置的对象必须配置! (这点有大神可以解释下嘛?)

 

对于这种情况@Inject不足或尴尬的情况,使用@ provides注释方法来满足依赖。方法的返回类型定义了它满足的依赖项。

 

For example, provideHeater() is invoked whenever a Heater is required:

例如:当需要Heater类对象时,就调用provideHeater()

@Provides static Heater provideHeater() {

  return new ElectricHeater();}

It’s possible for @Provides methods to have dependencies of their own. This one returns a Thermosiphon whenever a Pump is required:

@Provides标记的方法有可能拥有它们自己的依赖项。当需要Pump时,就返回一个 Thermosiphon 。

@Provides static Pump providePump(Thermosiphon pump) {

  return pump;

}

All @Provides methods must belong to a module. These are just classes that have an @Module annotation.

所有被@Provides标记的方法必须属于一个module类,module类仅仅是指被@Module注解的类

 

@Moduleclass DripCoffeeModule {

  @Provides static Heater provideHeater() {

    return new ElectricHeater();

  }

 

  @Provides static Pump providePump(Thermosiphon pump) {

    return pump;

  }}

 

By convention, @Provides methods are named with a provide prefix and module classes are named with a Module suffix.

按照惯例,@Provides方法以provide前缀命名,模块类(Module)以Module后缀命名。

Building the Graph建立图表

The @Inject and @Provides-annotated classes form a graph of objects, linked by their dependencies. Calling code like an application’s main method or an Android Application accesses that graph via a well-defined set of roots. In Dagger 2, that set is defined by an interface with methods that have no arguments and return the desired type. By applying the @Component annotation to such an interface and passing the module types to the modules parameter, Dagger 2 then fully generates an implementation of that contract.

@Inject入和@ provides注解类组成一个对象的图表,与他们的依赖关系相关联。像应用程序的主方法或Android应用程序那样调用代码,通过一组定义良好的根访问该图形。在Dagger 2中,该集合由一个具有没有参数且返回所需类型的方法的接口定义。通过将@Component注释应用到这样的接口,并将模块类型传递给模块参数,那么Dagger 2就会完全完成该契约的实现。

 

@Component(modules = DripCoffeeModule.class)

interface CoffeeShop {

  CoffeeMaker maker(); 

}

 

The implementation has the same name as the interface prefixed with Dagger. Obtain an instance by invoking the builder() method on that implementation and use the returned builder to set dependencies and build() a new instance.

 

生成的实现类与接口名相同,不过前缀为Dagger。通过在该实现上调用builder()方法来获取一个实例,并且利用该实例来设置依赖以及调用build()方法创建新的实例。

 

CoffeeShop coffeeShop = DaggerCoffeeShop.builder()   //获取实例

    .dripCoffeeModule(new DripCoffeeModule())   //设置依赖

.build();    //创建新的实例

 

Note: If your @Component is not a top-level type, the generated component’s name will include its enclosing types’ names, joined with an underscore. For example, this code:

class Foo {

  static class Bar {

    @Component

    interface BazComponent {}

  }}

would generate a component named DaggerFoo_Bar_BazComponent.

 

注意:如果@Component 标注的类,不是最顶级的类(内部类),那么生成的 component 组件的名称会包含该类的外部类的名称,通过下划线拼接将它们拼接起来。示例如下:

class Foo {

  static class Bar {

    @Component

    interface BazComponent {}

  }}

 

将生成一个名为DaggerFoo_Bar_BazComponent的组件。

 

Any module with an accessible default constructor can be elided as the builder will construct an instance automatically if none is set. And for any module whose @Provides methods are all static, the implementation doesn’t need an instance at all. If all dependencies can be constructed without the user creating a dependency instance, then the generated implementation will also have a create() method that can be used to get a new instance without having to deal with the builder.

 

任何具有可访问的默认构造函数的模块都可以省略,因为如果未设置实例,builder()将自动构造实例。对于任何@Provides注解的方法都是静态的模块,实现根本不需要实例。如果所有的依赖项都可以在使用者不创建依赖实例的情况下自动构建,那么生成的实现也会有一个create()方法,该方法可以用来获得一个新的实例,而不必与builder()打交道。

 

CoffeeShop coffeeShop = DaggerCoffeeShop.create();

 

Now, our CoffeeApp can simply use the Dagger-generated implementation of CoffeeShop to get a fully-injected CoffeeMaker.

 

现在,我们的CoffeeApp可以简单的使用Dagger生成的CoffeeShop实现得到一个完整注入的CoofeeMaker

 

public class CoffeeApp {

  public static void main(String[] args) {

    CoffeeShop coffeeShop = DaggerCoffeeShop.create();

    coffeeShop.maker().brew();

  }}

 

Now that the graph is constructed and the entry point is injected, we run our coffee maker app. Fun.

现在已经构建好了对象依赖图,并注入了入口点完成了依赖注入,我们运行了我们的咖啡机应用程序。

 

$ java -cp ... coffee.CoffeeApp

~ ~ ~ heating ~ ~ ~

=> => pumping => =>

 [_]P coffee! [_]P

 

Bindings in the graph对象依赖图的绑定

The example above shows how to construct a component with some of the more typical bindings, but there are a variety of mechanisms for contributing bindings to the graph. The following are available as dependencies and may be used to generate a well-formed component:

  • Those declared by @Provides methods within a @Module referenced directly by @Component.modules or transitively via @Module.includes
  • Any type with an @Inject constructor that is unscoped or has a @Scope annotation that matches one of the component’s scopes
  • The component provision methods of the component dependencies
  • The component itself
  • Unqualified builders for any included subcomponent
  • Provider or Lazy wrappers for any of the above bindings
  • A Provider of a Lazy of any of the above bindings (e.g., Provider<Lazy<CoffeeMaker>>)
  • A MembersInjector for any type

上面的示例展示了怎样通过一些典型的绑定去构造一个组件,但是这里有很多种机制可以为对象依赖图提供绑定。以下是一些可用的依赖关系也可以用来生成格式良好的组件。

 

  • @Module注解的类中被@Provides注解的方法可以直接被@Component.modules引用也可以通过@ComPonent.includes引用
  • 任何被@Inject注解的构造方法类型没有范围限制(表现为非单例),或者说@Scope注解的会与一个Component的范围匹配(表现为在Component范围内单例)。
  • Component提供组件依赖关系的方法。(表现为:Component接口中定义依赖关系的方法)
  • 组件(Component)本身
  • 任何包含的子组件的没有限制的构建器
  • 任何上述绑定的提供者Providers或惰性包装器Lazy wrappers
  • 上面任何绑定的懒惰(Lazy)的提供者(Providr) (e.g., Provider<Lazy<CoffeeMaker>>)
  • 用于任何类型的MemversInjector

Singletons and Scoped Bindings单例及作用域绑定

Annotate an @Provides method or injectable class with @Singleton. The graph will use a single instance of the value for all of its clients.

用@Singleton注解@Providers注解的方法或者注解可注入的类,对象依赖图将会为其所有client创建唯一实例(单例)。

@Provides 

@Singleton 

static Heater provideHeater() {

  return new ElectricHeater();

}

The @Singleton annotation on an injectable class also serves as documentation. It reminds potential maintainers that this class may be shared by multiple threads.

在可注入类上的@Singleton注解也充当文档,它同时提醒潜在的维护人员这个类可以被多个线程共享。

@Singleton

class CoffeeMaker {

  ...}

Since Dagger 2 associates scoped instances in the graph with instances of component implementations, the components themselves need to declare which scope they intend to represent. For example, it wouldn’t make any sense to have a @Singleton binding and a @RequestScoped binding in the same component because those scopes have different lifecycles and thus must live in components with different lifecycles. To declare that a component is associated with a given scope, simply apply the scope annotation to the component interface.

因为Dagger2将对象依赖图中实例的范围和Component生成的实例关联起来,因此Component本身需要声明他们打算表示的范围。例如,在一个Component上同时绑定@Singleton注解和@RequestScoped注解没有任何意义,因为这些注解指明的生命周期不同,所以他们必须注解在不同声明周期的Component上。要声明一个Component和给定的范围相关联,只需要用@Scope注解到Component接口上。

@Component(modules = DripCoffeeModule.class)

@Singleton

interface CoffeeShop {

  CoffeeMaker maker();

}

Components may have multiple scope annotations applied. This declares that they are all aliases to the same scope, and so that component may include scoped bindings with any of the scopes it declares.

Components中可能应用了多个@Scope注解,这声明了它们是同一个@Scope的别名,而且因此Component可能包括与任何其声明的作用域范围绑定。

Reusable scope可重用的作用域

Sometimes you want to limit the number of times an @Inject-constructed class is instantiated or a @Provides method is called, but you don’t need to guarantee that the exact same instance is used during the lifetime of any particular component or subcomponent. This can be useful in environments such as Android, where allocations can be expensive.

有时候你想要限制@Inject构造器类被实例化或者@Provides方法被调用的次数,而且不需要确保在任何component或者subcomponent的生命周期存在同一实例。这在诸如Android这样的环境中是很有用的,因为在那里,分配成本很高。

For these bindings, you can apply @Reusable scope. @Reusable-scoped bindings, unlike other scopes, are not associated with any single component; instead, each component that actually uses the binding will cache the returned or instantiated object.

对于这些绑定,可以使用@Reusable作用域。@Reusable作用域绑定,不像其他作用域绑定一样需要关联一个component。相反,真正使用@Reusable作用域绑定的component将会缓存一个返回值或者对象实例。

That means that if you install a module with a @Reusable binding in a component, but only a subcomponent actually uses the binding, then only that subcomponent will cache the binding’s object. If two subcomponents that do not share an ancestor each use the binding, each of them will cache its own object. If a component’s ancestor has already cached the object, the subcomponent will reuse it.

这意味着如果你在component上安装了一个带有@Reusable绑定的module,但却只有一个subcomponent实际用到了这个绑定。那么只有那个subcomponent会缓存这绑定的对象。如果两个subcompomponent不共享同一个祖先各自使用绑定,每个subcomponent都会缓存他们自己的对象。如果一个component的祖先已经缓存了对象,subcomponent会重用它。

There is no guarantee that the component will call the binding only once, so applying @Reusable to bindings that return mutable objects, or objects where it’s important to refer to the same instance, is dangerous. It’s safe to use @Reusable for immutable objects that you would leave unscoped if you didn’t care how many times they were allocated.

这里不能保证component只会调用一次,所以应用@Reusable绑定可能返回不确定对象,这时在重要的地方引用同一实例是很危险的。当你不关系对象被分配多少次时使用@Reusable是安全的。

Releasable references可释放的引用

DEPRECATED: This feature is deprecated and scheduled for removal in July 2018.

(弃用:这个功能已经启用而且计划于2018年移除)

When a binding uses a scope annotation, that means that the component object holds a reference to the bound object until the component object itself is garbage-collected. In memory-sensitive environments such as Android, you may want to let scoped objects that are not currently being used be deleted during garbage collection when the application is under memory pressure.

In that case, you can define a scope and annotate it with @CanReleaseReferences.

当一个绑定使用了@Scope注解,这意味着component对象持有一个对象的引用知道component对象被gc回收。像在Android这样内存敏感的环境中,当应用程序处于内存压力下时,你可能希望当前没有使用的@Scope对象在gc回收期间删除。

在这种条件下,你可以定义@Scope并@CanReleaseReferences注解它。

@Documented

@Retention(RUNTIME)

@CanReleaseReferences

@Scope

public @interface MyScope {

}

When you determine that you want to allow objects held in that scope to be deleted during garbage collection if they’re not currently being used by some other object, you can inject a ReleasableReferenceManager object for your scope and call releaseStrongReferences() on it, which will make the component hold a WeakReference to the object instead of a strong reference:

当您确定要允许在垃圾收集期间删除该范围内的对象时(如果其他对象当前没有使用这些对象)。您可以为您的范围注入一个ReleasableReferenceManager对象,并在其上调用releaseStrongReferences(),这将使组件持有对象的弱引用,而不是强引用:

If you determine that the memory pressure has receded, then you can restore the strong references for any cached objects that have not yet been deleted during garbage collection by calling restoreStrongReferences():

如果你确定内存压力已经减少,那么你可以通过调用restoreStrongReferences()来恢复在gc回收期间尚未删除任何缓存对象的强引用。

Lazy injections懒注入

Sometimes you need an object to be instantiated lazily. For any binding T, you can create a Lazy<T> which defers instantiation until the first call to Lazy<T>’s get() method. If T is a singleton, then Lazy<T> will be the same instance for all injections within the ObjectGraph. Otherwise, each injection site will get its own Lazy<T> instance. Regardless, subsequent calls to any given instance of Lazy<T> will return the same underlying instance of T.

有时候你需要延迟加载一个对象,对于任何绑定T,你可以创建Lazy<T>,它的实例化会延迟到第一次调用Lazy<T>的get方法。如果T是单例的,那么在对象依赖图(ObjectGraph)中所有注入都是同一实例。否则,每个注入都会有自己的Lazy<T>实例。无论如何,后续调用任何给定Lazy<T>实例都将会返回对象T的同一底层实例。

Provider injectionsProvider 注入

Sometimes you need multiple instances to be returned instead of just injecting a single value. While you have several options (Factories, Builders, etc.), one option is to inject a Provider<T> instead of just T. A Provider<T> invokes the binding logic for T each time .get() is called. If that binding logic is an @Inject constructor, a new instance will be created, but a @Provides method has no such guarantee.

有时候你需要返回多个实例而不是仅仅注入一个值,虽然你有好几个选项(工厂,构造器,等),一个选项是注入Provider<T>而不是注入T,每次调用Provider<T>的get()方法都会调用一次绑定逻辑。如果绑定逻辑是一个@Inject构造器,将会创建一个新的实例,但是如果是@Provides注解的方法就不能保证了。

Note: Injecting Provider<T> has the possibility of creating confusing code, and may be a design smell of mis-scoped or mis-structured objects in your graph. Often you will want to use a factory or a Lazy<T> or re-organize the lifetimes and structure of your code to be able to just inject a T. Injecting Provider<T> can, however, be a life saver in some cases. A common use is when you must use a legacy architecture that doesn’t line up with your object’s natural lifetimes (e.g. servlets are singletons by design, but only are valid in the context of request-specfic data).

注意:注入Provider<T>可能会创建令人迷惑的代码,而且可能在对象依赖图中设计错误范围或者错误结构的对象。通常你会想用工厂或者Lazy<T>或者重新组织代码的生命周期和结构使得可以注入一个T。然而,在某些情况注入Provider<T>可以成为救命稻草。一个常见的用法是当你必须使用与你对象生命周期不一致的传统架构时。(例如:servlets被设计为单例,但是只在上下文中特定数据有效)

Qualifiers限定符

Sometimes the type alone is insufficient to identify a dependency. For example, a sophisticated coffee maker app may want separate heaters for the water and the hot plate.

In this case, we add a qualifier annotation. This is any annotation that itself has a @Qualifier annotation. Here’s the declaration of @Named, a qualifier annotation included in javax.inject:

有时候类型不足以识别依赖性,例如,一个复杂的咖啡机应该程序可能为水和热板提供单独的加热器。(译者注:通过之前的所有实例,大家都可以发现Dagger注入是通过类型来识别依赖的,那么当定义了同一类型的多个对象时就需要Qualifiers来帮助我们识别需要绑定的对象)

在本例中,我们添加了限定符注解。这本身是一个注解但是又被@Qualifier注解,这是@Named注解的声明,它是一个被javax.inject包含的限定符注解。

You can create your own qualifier annotations, or just use @Named. Apply qualifiers by annotating the field or parameter of interest. The type and qualifier annotation will both be used to identify the dependency.

你可以创建你自己的限定符注解,或者只使用@Named注解。通过注解感兴趣的字段和参数来应用限定符。类型和限定符注解会一起用于识别依赖。

Supply qualified values by annotating the corresponding @Provides method.

通过注解相应的@Provides注解的方法来提供限定值。

Dependencies may not have multiple qualifier annotations.

依赖关系可能不会有多个限定符注解。

Optional bindings可选的绑定

If you want a binding to work even if some dependency is not bound in the component, you can add a @BindsOptionalOf method to a module:

如果你想要绑定工作,即使一些依赖项没有绑定到component,你可以向模块添加@BindsOptionalOf方法。

That means that @Inject constructors and members and @Provides methods can depend on an Optional<CoffeeCozy> object. If there is a binding for CoffeeCozy in the component, the Optional will be present; if there is no binding for CoffeeCozy, the Optional will be absent.

Specifically, you can inject any of the following:

  • Optional<CoffeeCozy> (unless there is a @Nullable binding for CoffeeCozy; see below)
  • Optional<Provider<CoffeeCozy>>
  • Optional<Lazy<CoffeeCozy>>
  • Optional<Provider<Lazy<CoffeeCozy>>>

(You could also inject a Provider or Lazy or Provider of Lazy of any of those, but that isn’t very useful.)

这意味着@Inject构造器和成员以及@Provides方法可以依赖于Optional<CoffeeCozy>对象,如果component绑定了这个CoffeeCozy,将会存在Optional;如果component没有绑定CoffeeCozy,Optional将会缺省。

具体来说,你可以注入以下任何一种:

  • Optional<CoffeeCozy> (除非CoffeeCozy上绑定了@Nullable,见下文)
  • Optional<Provider<CoffeeCozy>>
  • Optional<Lazy<CoffeeCozy>>
  • Optional<Provider<Lazy<CoffeeCozy>>>

(你也可以为其中任何一个注入Provider,Lazy或者Provider<Lazy<> >,但是并不是特别有用)

If there is a binding for CoffeeCozy, and that binding is @Nullable, then it is a compile-time error to inject Optional<CoffeeCozy>, because Optional cannot contain null. You can always inject the other forms, because Provider and Lazy can always return null from their get() methods.

An optional binding that is absent in one component can be present in a subcomponent if the subcomponent includes a binding for the underlying type.

You can use either Guava’s Optional or Java 8’s Optional.

如果CoffeeCozy有绑定,并且绑定的是@Nullable,那么注入Optional<COffeeCozy>会产生编译时错误,因为Optional不能包含null。你总是可以注入其它格式,因为Provider和Lazy的get()方法总是可以返回一个null。

如果subcomponent包含底层(基础)类型的绑定,那么component中没有的optional绑定可以出现在subcomponent中。

你可以使用Guava’s OptionaL 或者 Java’s Optional。

Binding Instances绑定实例

Often you have data available at the time you’re building the component. For example, suppose you have an application that uses command-line args; you might want to bind those args in your component.

Perhaps your app takes a single argument representing the user’s name that you’d like to inject as @UserName String. You can add a method annotated @BindsInstance to the component builder to allow that instance to be injected in the component.

通常你在绑定component的时候有可用的数据,比如,假如你有一个使用命令行参数的应用程序;你可能希望将这些参数绑定到你的component上。

可能你的应用程序只接受一个参数,该参数表示用户名,你可能以@Username字符串的形式注入。在component中你可以向component builder添加@BindsInstance注解的方法,去允许可以注入该实例。

Your app then might look like你的应用程序看起来可能会是这样

In the above example, injecting @UserName String in the component will use the instance provided to the Builder when calling this method. Before building the component, all @BindsInstance methods must be called, passing a non-null value (with the exception of @Nullable bindings below).

If the parameter to a @BindsInstance method is marked @Nullable, then the binding will be considered “nullable” in the same way as a @Provides method is nullable: injection sites must also mark it @Nullable, and null is an acceptable value for the binding. Moreover, users of the Builder may omit calling the method, and the component will treat the instance as null.

@BindsInstance methods should be preferred to writing a @Module with constructor arguments and immediately providing those values.

在上面的例子中,在component中注入@UserName字符串将使用在调用这个方法时提供给Builder的实例。在构建compoent之前,必须调用所有的@BindsInstance注解的方法,传递一个非空值(下面@Nullable绑定除外)。

如果@BindsInstance方法的参数被标记为@Nullable,那么这个绑定在被认为是“nullable”,就像@Provides方法是nullable一样;注入点必须是被标记为@Nullable,null是绑定中可以接受的值。此外,Builder的用户可能会忽略调用该方法,component将把该实例视为null。

@BindsInstance方法应该更倾向于用构造方法参数编写@Mudule,并立即提供这些参数。

(译者注:@BindsInstace主要用于java(非Android),笔者并没有实际操作过,所以理解可能存在偏差)

Compile-time Validation运行时验证

The Dagger annotation processor is strict and will cause a compiler error if any bindings are invalid or incomplete. For example, this module is installed in a component, which is missing a binding for Executor:

Dagger注解处理器是严格的,如果任一绑定是无效或者不完整的将会报编译错误。例如:这个component安装了一个mudule,但是component缺少Executor绑定。

When compiling it, javac rejects the missing binding:

在编译时,javac拒绝了这个错误的绑定。

 

[ERROR] COMPILATION ERROR :

[ERROR] error: java.util.concurrent.Executor cannot be provided without an @Provides-annotated method.

 

Fix the problem by adding an @Provides-annotated method for Executor to any of the modules in the component. While @Inject, @Module and @Provides annotations are validated individually, all validation of the relationship between bindings happens at the @Component level. Dagger 1 relied strictly on @Module-level validation (which may or may not have reflected runtime behavior), but Dagger 2 elides such validation (and the accompanying configuration parameters on @Module) in favor of full graph validation.

通过向component中添加一个@Provides注解的方法生成Executor来解决该问题。虽然@Inject,@Module和@Provides注解是单独验证的,但是所有绑定关系的验证都发生在component级别。Dagger1严格依赖于@Mudule级别的验证(可能导致运行时反射行为),但是Dagger2省略了这样的验证(以及@Module附加的参数配置),以支持完整的对象依赖图验证。

Compile-time Code Generation编译时代码生成

Dagger’s annotation processor may also generate source files with names like CoffeeMaker_Factory.java or CoffeeMaker_MembersInjector.java. These files are Dagger implementation details. You shouldn’t need to use them directly, though they can be handy when step-debugging through an injection. The only generated types you should refer to in your code are the ones Prefixed with Dagger for your component.

Dagger的注解处理器可能会生成名字为CoffeeMaker_Factory.java或者CoffeeMaker_MembersInjector.java的源文件。这些文件是Dagger实现的细节。你不需要直接使用他们,虽然在通过注入进行单步调试时会很方便。你应该在代码中使用component加上前缀Dagger 来引用仅有的实例类型。(译者注:就示例中咖啡机而言,引用实例为:DaggerCoffeeMaker)

Using Dagger In Your Build在构建中使用Dagger

You will need to include the dagger-2.X.jar in your application’s runtime. In order to activate code generation you will need to include dagger-compiler-2.X.jar in your build at compile time. See the README for more information.

你将需要在应用程序运行时包含dagger-2.x.jar包。为了激活代码生成,你需要在编译时构建中包含dagger-comPiler-2.x.jar包。请参阅https://github.com/google/dagger/blob/master/README.md#installation以获取更多信息。

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值