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

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

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

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

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的类(即使该类不需要该类用于任何其他目的)也是非常必要的。

恕我直言,不得不手动注入一个上下文实例来访问注入器本身听起来有点反直观。

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

其他人说,静态的东西不能在测试中被嘲笑,这是真的,尽管我不确定我完全得到这个,因为它是能够轻松模拟/测试的DI模式,而不是注入器本身,所以我们为什么要模拟注射器本身?

这些替代方案有哪些优缺点? 除了这里已经提到的其他可能的替代方案吗?


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

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


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

为什么静态变量被视为邪恶?

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

链接地址: http://www.djcxy.com/p/36035.html

上一篇: Dagger 2 on Android. Different ways to store and access a @Singleton Component

下一篇: How Dynamically change URL in a WCF Custom Behavior