使用 Dagger 2 创建单例的最简单方法?

Simplest way to create a Singleton w/ Dagger 2?

我需要设置模块、提供程序和接口(组件)吗? 似乎仅仅为了能够注入一个单例就需要相当多的开销。

有人可以提供一个使用 Dagger 2 的简单单例示例吗? (还展示了如何设置单例的属性,比如上下文,这样你就不需要在每次使用单例时都传入它)

您只需要模块来处理您无法使用 @Inject 构造函数注释的内容(因为例如,框架会为您创建它 - 例如上下文)。如果不能添加@Inject构造函数,还需要在组件中指定一个void inject(...)方法。

但是,如果您可以使用 @Inject 构造函数创建它,那么 @Inject 也可以用作字段注释

@Component(modules={ContextModule.class})
@Singleton
public interface SingletonComponent {
    void inject(MainActivity mainActivity);
}

@Module
public class ContextModule {
    Context context;

    public ContextModule(Context context) {
        this.context = context;
    }

    @Provides
    Context context() {
        return context;
    }
}

@Singleton
public class MyOtherSingleton {
    @Inject
    public MyOtherSingleton() {
    }
}


@Singleton
public class MySingleton {
    @Inject Context context;
    @Inject MyOtherSingleton myOtherSingleton;

    @Inject
    public MySingleton() {
    }
}

你也可以做构造参数

private final Context context;
private final MyOtherSingleton myOtherSingleton;

@Inject
public MySingleton(Context context, MyOtherSingleton myOtherSingleton) {
    this.context = context;
    this.myOtherSingleton = myOtherSingleton;
}

SingletonComponent singletonComponent = DaggerSingletonComponent.builder()
           .contextModule(CustomApplication.this)
           .build();

// and elsewhere

@Inject
MySingleton mySingleton;

// ...
    singletonComponent.inject(this);

验证有效:

08-23 04:39:28.418 com.zhuinden.rxrealm D/DogView: My singleton has [com.zhuinden.rxrealm.application.CustomApplication@53348a58] and [com.zhuinden.rxrealm.application.injection.test.MyOtherSingleton@5336bb74]
08-23 04:39:36.422 com.zhuinden.rxrealm D/CatView: My singleton has [com.zhuinden.rxrealm.application.CustomApplication@53348a58] and [com.zhuinden.rxrealm.application.injection.test.MyOtherSingleton@5336bb74]

这是一个简化的(不完全精确 -- 检查下面的链接)文本,逐渐解释 Dagger2 及其背后的想法。我希望您在阅读本文后能够阅读并理解有关 Dagger2 的其他详细信息。

不要关注单例这个词。 Dagger2(忘记 dagger,使用 dagger2)的存在是为了加强对象范围。不是我们通常谈论的范围(classes、方法、循环),而是架构级别的范围(您定义那些层)。

Android中的一些典型层是Application、Activity和Fragment。如您所知,您的 android 应用程序仅获得一个应用程序实例 class。 Activity class 的许多实例和 Fragment class.

的许多实例

您想使您的应用程序保持美观和干净,并希望将您的对象保持在它们所属的位置(强制语义)。这些对象需要在某处创建(通常你必须输入工厂classes/methods/projects——最后一个是个笑话),创建实用程序需要在某处调用,你需要将这些对象从某处传递到它们所属的地方!

有很多地方需要输入 (通常 class 的名字很奇怪) 并将这些对象从创建它们的地方传递到它们所属的地方可以是相当大的挑战。尤其是当许多不同的 class 都使用您的那个特殊对象时。

Dagger2 来救援!基本上,您需要了解两个术语。组件和模块。

组件在这里注入。他们将需要构建的对象注入您的 classes。组件只注入,它们不创建对象。那么谁创建对象?

模块创建对象,组件将这些对象注入到需要构建的 classes 中。模块充满了 provideInsertName 方法。这些方法创建您需要传递给需要它们的 classes 的对象。 provide 方法将始终创建一个新对象,或者它将重用 (singleton) 已创建的对象,如果该 provide 方法使用 @Scope 注释(您需要键入一个新的范围注释,但这是细节)。提供方法的名称并不重要。重要的是这些方法的 return 类型 (记住以后会有用的信息).

当您键入您的组件时,您需要说明哪些模块与该组件关联,并且在组件实例化期间,您必须将关联的模块实例传递给该组件构造函数。组件和模块一起构成一个平均注入机。

在您认为组件应该注入的层中实例化您的组件(Dagger2 为您的组件生成构建器classes)。例如,您在 Application class 中创建了一个 ApplicationComponent 实例。 ApplicationComponent 注入的对象只创建一次,当 ApplicationComponent 实例存在时它们就存在 (在注入期间它们将被获取,而不是重新创建)。 ApplicationComponent 实例存在而 Application 实例存在 (因此在 Android 环境中基本上是 always/during 应用程序生命周期).

您可以用 Activity class 重复相同的故事。在 Activity class 中实例化 ActivityComponent,当 Activity 存在时,该 Component 存在。请注意 ActivityComponent 注入的对象仅在 ActivityComponent(Activity class 实例)存在时才存在。这就是 Dagger2 的美妙之处。属于 Activity 层的对象实际上是在 Activity 层范围内。

注意:组件可以相互依赖。您的 ActivityComponent 可以依赖于您的 ApplicationComponent,因此 Activity 层可以使用来自 Application 层 的对象(但不是其他方式,那是糟糕的设计)。这样,组件就形成了一个依赖树,使得对象的获取和注入非常高效。

读完这篇文章后(祝贺你好先生)我建议你看看这个 link and checking out Jake Wharton's talk on Dagger2