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

Yoh*_*n D 6 java android dagger-2

我有这个初始化书法默认配置的代码。

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()
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

我想在我的项目中使用 Dagger 2,但我不完全了解我应该创建哪些类以及将代码移动到哪里以保持项目干净?

Dav*_*jak 3

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

\n\n

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

\n\n

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

\n\n

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

\n\n

另一方面,如果您确实需要(或想要)能够测试它,或者只是有一个干净的设计......

\n\n

...包裹它

\n\n

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

\n\n
public interface CalligraphyManager {\n    /**\n     *  Called on app start up to initialize\n     */\n     void init();\n\n     // other methods, like wrapping context for activity\n     Context wrap(Context context);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

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

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

\n\n
public class MyApplication extends Application {\n\n    @Inject\n    CalligraphyManager mCalligraphy;\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n\n        mComponent = DaggerAppComponent.builder()\n                .appModule(new AppModule(this))\n                .build();\n        mComponent.inject(this);\n\n        // call the initialization\n        mCalligraphy.init();\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

其他一切都如常。您的应用程序组件图中有一个单例对象,因此您可以将相同的对象注入到您的活动中,并在适当的情况下调用`wrap\xc2\xb4。

\n\n

测试/模拟怎么样?

\n\n

由于这样做的全部原因是为了使其“可测试”,因此您现在可以轻松提供模拟/存根对象。

\n\n

创建管理器的另一个实现,其中init()不执行任何操作,并且wrap(Context)仅返回相同的上下文 - 一个简单的存根对象。

\n