使用 Dagger 2 时,我应该将库初始化移动到哪里?

Where should I move a library initialization when using Dagger 2?

我有这段代码可以初始化 Calligraphy 默认配置。

public class MyApplication extends Application {

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

        // The initialization I want to move
        CalligraphyConfig.initDefault(new CalligraphyConfig.Builder()
                        .setDefaultFontPath("fonts/MyFont.ttf")
                        .build()
        );
    }
}

我想在我的项目中使用 Dagger 2,但我不完全理解 类 我应该创建什么以及将此代码移到哪里才能保持项目整洁?

简而言之,你可能不会移动任何东西。这个库的问题是它使用静态方法进行初始化和使用。尝试进行依赖注入时,静态方法很痛苦。

图书馆(或者你为什么不改变任何东西)

看起来这个库是 'just' 关于通过包装上下文来切换使用的字体。因此它并没有真正为您的项目提供业务逻辑,而只是增加了您的视图/UI.

如果您希望能够进行单元测试(注入模拟)或轻松交换模块/行为,那么注入依赖项而不是仅仅调用静态方法是最有用的。在全局更​​改字体的情况下,两者似乎都不太可能。

另一方面,如果您确实需要(或希望)能够对其进行测试,或者只是拥有一个简洁的设计...

...包起来

静态方法很痛苦,因为你不能让对象持有逻辑。除非你把它们包起来。要使用静态方法正确执行 DI,您必须定义自己的接口。

public interface CalligraphyManager {
    /**
     *  Called on app start up to initialize
     */
     void init();

     // other methods, like wrapping context for activity
     Context wrap(Context context);
}

您现在有一些管理器可以访问静态方法。实现应该相当简单,因为你想做适当的 DI,init() 所需的应用程序上下文和路径将被传递到你的实现的构造函数中。因此,您的管理器的创建可以由您的 ApplicationModule 处理——只需添加一些提供方法

@Singleton
@Provides
// You would also have to provide the path from somewhere or hardcode it
// left as an exercise for the reader
CalligraphyManager provideCalligraphyManager(Context context, String path) {
    return new ActualCalligraphyManager(context, path);
}

您的应用程序将如下所示:

public class MyApplication extends Application {

    @Inject
    CalligraphyManager mCalligraphy;

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

        mComponent = DaggerAppComponent.builder()
                .appModule(new AppModule(this))
                .build();
        mComponent.inject(this);

        // call the initialization
        mCalligraphy.init();
    }
}

其他一切如常。您的应用程序组件图中有一个单例对象,因此您可以将相同的对象注入到您的活动中并在适当的地方调用“wrap”。

测试/模拟呢?

由于这样做的全部原因是为了实现它 'testable',您现在可以轻松地提供模拟/存根对象。

创建管理器的另一个实现,其中 init() 什么都不做,wrap(Context) 只是 return 相同的上下文——一个简单的存根对象。