我有这个代码初始化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但是我不完全理解我应该创建哪些类以及在何处移动此代码以保持项目清洁?
答案 0 :(得分:3)
简而言之,你可能不会移动任何东西。这个库的问题在于它使用静态方法进行初始化和利用。尝试依赖注入时,静态方法很痛苦。
看起来这个库“只是”通过包装上下文来切换使用过的字体。因此,它并不真正为您的项目提供业务逻辑,而只是添加到您的视图/ 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”。
由于这样做的全部原因是为了使其“可测试”,您现在可以轻松提供模拟/存根对象。
创建管理器的另一个实现,其中init()
什么也不做,wrap(Context)
只返回相同的上下文 - 一个简单的存根对象。