Android上的Dagger 2。存储和访问@Singleton组件的不同方法

时间:2016-09-01 06:55:17

标签: java android dagger-2

这是关于如何存储@Singleton作用域Dagger 2组件的第N个问题,其寿命应该等于应用程序的生命周期。

在使用Dagger 2的Android应用程序中,通常至少有一个组件是@Singleton范围,应该持续所有应用程序的生命周期:由于这些要求,它通常被初始化并存储在自定义Application类中。

由于我们的应用程序的所有部分都必须可以访问此Component的实例,所以我看到过这样的代码:

1。将组件存储在应用程序类内的公共静态变量中。

public class App extends Application {

    public static AppComponent appComponent;

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

        appComponent = DaggerAppComponent.builder()
                .appModule(new AppModule(this)).build();
    }
}

通过以下方式可以在任何其他地方访问它:

App.appComponent.inject(this);

2。将组件存储在应用程序实例内的私有变量中,并为其创建静态访问器。

public class App extends Application {

    private static AppComponent appComponent;

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

        appComponent = DaggerAppComponent.builder()
                .appModule(new AppModule(this)).build();
    }

    public static AppComponent getAppComponent() {
        return appComponent;
    }
}

通过以下方式可以在任何其他地方访问它:

App.getAppComponent().inject(this);

3。将组件存储在应用程序实例内的私有变量中,并为其创建非静态访问器。

public class App extends Application {

    private AppComponent appComponent;

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

        appComponent = DaggerAppComponent.builder()
                .appModule(new AppModule(this)).build();
    }

    public AppComponent getAppComponent() {
        return appComponent;
    }
}

这样只能从包含对Context的引用的类实例访问它:

// From within an Activity.
((App) getApplication()).getAppComponent().inject(this);

// From within a Fragment.
((App) getActivity().getApplication()).getAppComponent().inject(this);

// From within any other class which holds a reference to a Context. 
((App) context.getApplicationContext()).getAppComponent().inject(this);

这种最后一种方式使得将Context引用传递给任何愿意访问Component的类是非常必要的(即使该类不需要该Context用于任何其他目的)。

IMHO必须“手动注入”一个Context实例才能访问注入器本身听起来有点反直觉。

另一方面,许多人建议不要使用静态变量但是:为什么?如果对象必须在应用程序的生命周期内保留在内存中(这意味着JVM实例的整个生命周期),如果它存储在静态变量中会出现什么问题呢?

其他人说静态的东西不能在测试中被嘲笑而且这是真的,虽然我不确定我是否完全得到这个,因为它是DI模式,可以轻松进行模拟/测试,而不是注入器本身,所以为什么会我们想模拟注射器本身吗?

这些替代方案的优缺点是什么?除了这里已经提到的那些之外,还有其他可能的选择吗?

2 个答案:

答案 0 :(得分:5)

使用1和2您正在使用静态引用。这是一个关于为什么要避免它们的好主题

Why are static variables considered evil?

所以剩下的唯一选择是第3个。这就是我在项目中使用的内容。 关于是否应该将上下文作为参数传递,取决于项目的体系结构以及如何设计Dagger依赖项。就个人而言,我没有这个问题,因为我只注入活动/片段。你能给我一个例子,你需要传递上下文来注入依赖项吗?

答案 1 :(得分:2)

我使用方法#2。方法#1的主要问题是你暴露了一个可变字段。如果您的模块不需要构建Context,则可以创建字段final。但作为一种风格问题,我仍然不愿意暴露领域。

您通常应该避免全局状态,特别是在Android中,因为组件和VM本身的复杂且有时不直观的生命周期。但Application是此规则的例外。每个VM只存在一个实例,并且在创建任何其他组件之前,它的onCreate()方法只调用一次。这使得它成为创建和存储静态单例的可接受的地方。