如何使用 dagger2 注入没有任何 activity 或片段的 java class
How to inject into a java class that doesn't have any activity or fragment using dagger2
Android Studio 2.2.2
我有一个NewsListModelImp
class是MVP中的模型
我想将我的改造服务注入到模型中。但是,由于 NewsListModelImp
不包含对上下文或 activity 的任何引用,我无法调用 getApplication()
。如果你在 activity 或片段中,你会这样做。我不想在 NewsListModeImp
的构造函数中传递任何上下文或 activity,因为它必须来自演示者,我想避免那里有任何 android 东西。
public class NewsListModelImp implements NewsListModelContract {
@Inject
NYTimesSearchService mNYTimesSearchService;
public NewsListModelImp() {
((NYTimesSearchApplication)getApplication()).getAppComponent().inject(this);
}
}
我的申请class
public class NYTimesSearchApplication extends Application {
private AppComponent mAppComponent;
public void onCreate() {
super.onCreate();
/* Setup dependency injection */
createAppComponent();
}
private void createAppComponent() {
mAppComponent = DaggerAppComponent
.builder()
.retrofitModule(new RetrofitModule())
.build();
}
public AppComponent getAppComponent() {
return mAppComponent;
}
}
我提供的模块
@Module
public class RetrofitModule {
private Retrofit retrofit() {
return new Retrofit
.Builder()
.baseUrl(Constants.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
@Provides
@Singleton
public NYTimesSearchService providesNYTimesSearch() {
return retrofit().create(NYTimesSearchService.class);
}
}
我的应用组件
@Singleton
@Component(modules = {RetrofitModule.class})
public interface AppComponent {
void inject(NewsListModelImp target);
}
非常感谢您的任何建议,
Dagger-2
重复工作。因此,如果在 Activity
(或 Fragment
)内部对象被注入并且它的构造函数被正确地用 @Inject
注释注释,构造函数的参数也将被注入。
假设在您要注入的应用程序中:
@Inject NyTimesPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((NYTimesSearchApplication) getApplication()).getAppComponent().inject(this);
}
NyTimesPresenter
的构造函数必须注解@Inject
:
public class NyTimesPresenter {
NewsListModelImp newsListModel;
@Inject
public NyTimesPresenter(NewsListModelImp newsListModel) {
this.newsListModel = newsListModel;
}
}
NewsListModelImp
构造函数也必须用 @Inject
:
注释
public class NewsListModelImp implements NewsListModelContract {
NYTimesSearchService mNYTimesSearchService;
@Inject
public NewsListModelImp(NYTimesSearchService nYTimesSearchService) {
this.mNYTimesSearchService = nYTimesSearchService;
}
}
然后一切都将正确注入。
为什么要将参数作为构造函数的参数传递给class?这样的设计模式符合SOLID principles
。对象依赖项被注入到对象中,而不是在对象内部创建,这样的代码很容易测试(在测试中,依赖项可以被 Mock
替换)
额外信息:
可以注入实现特定接口的对象。 here 描述了这种技术。在你的情况下 NyTimesPresenter
可以有 NewsListModelContract
因为它是依赖而不是 NewsListModelImp
。为此,请将另一个模块添加到您的 AppComponent
:
@Singleton
@Component(
modules = {
RetrofitModule.class,
AppModule.class
})
public interface AppComponent {
AppComponent
提供具体 class 实现接口的方法应该如下所示:
@Singleton
@Module
public abstract class AppModule {
@Binds
public abstract NewsListModelContract provideNewsListModelContract(NewsListModelImp newsListModelImp);
}
NyTimesPresenter
的实现应该改变(只是用它实现的接口替换具体的 class):
public class NyTimesPresenter {
NewsListModelContract newsListModel;
@Inject
public NyTimesPresenter(NewsListModelContract newsListModel) {
this.newsListModel = newsListModel;
}
}
Android Studio 2.2.2
我有一个NewsListModelImp
class是MVP中的模型
我想将我的改造服务注入到模型中。但是,由于 NewsListModelImp
不包含对上下文或 activity 的任何引用,我无法调用 getApplication()
。如果你在 activity 或片段中,你会这样做。我不想在 NewsListModeImp
的构造函数中传递任何上下文或 activity,因为它必须来自演示者,我想避免那里有任何 android 东西。
public class NewsListModelImp implements NewsListModelContract {
@Inject
NYTimesSearchService mNYTimesSearchService;
public NewsListModelImp() {
((NYTimesSearchApplication)getApplication()).getAppComponent().inject(this);
}
}
我的申请class
public class NYTimesSearchApplication extends Application {
private AppComponent mAppComponent;
public void onCreate() {
super.onCreate();
/* Setup dependency injection */
createAppComponent();
}
private void createAppComponent() {
mAppComponent = DaggerAppComponent
.builder()
.retrofitModule(new RetrofitModule())
.build();
}
public AppComponent getAppComponent() {
return mAppComponent;
}
}
我提供的模块
@Module
public class RetrofitModule {
private Retrofit retrofit() {
return new Retrofit
.Builder()
.baseUrl(Constants.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
@Provides
@Singleton
public NYTimesSearchService providesNYTimesSearch() {
return retrofit().create(NYTimesSearchService.class);
}
}
我的应用组件
@Singleton
@Component(modules = {RetrofitModule.class})
public interface AppComponent {
void inject(NewsListModelImp target);
}
非常感谢您的任何建议,
Dagger-2
重复工作。因此,如果在 Activity
(或 Fragment
)内部对象被注入并且它的构造函数被正确地用 @Inject
注释注释,构造函数的参数也将被注入。
假设在您要注入的应用程序中:
@Inject NyTimesPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((NYTimesSearchApplication) getApplication()).getAppComponent().inject(this);
}
NyTimesPresenter
的构造函数必须注解@Inject
:
public class NyTimesPresenter {
NewsListModelImp newsListModel;
@Inject
public NyTimesPresenter(NewsListModelImp newsListModel) {
this.newsListModel = newsListModel;
}
}
NewsListModelImp
构造函数也必须用 @Inject
:
public class NewsListModelImp implements NewsListModelContract {
NYTimesSearchService mNYTimesSearchService;
@Inject
public NewsListModelImp(NYTimesSearchService nYTimesSearchService) {
this.mNYTimesSearchService = nYTimesSearchService;
}
}
然后一切都将正确注入。
为什么要将参数作为构造函数的参数传递给class?这样的设计模式符合SOLID principles
。对象依赖项被注入到对象中,而不是在对象内部创建,这样的代码很容易测试(在测试中,依赖项可以被 Mock
替换)
额外信息:
可以注入实现特定接口的对象。 here 描述了这种技术。在你的情况下 NyTimesPresenter
可以有 NewsListModelContract
因为它是依赖而不是 NewsListModelImp
。为此,请将另一个模块添加到您的 AppComponent
:
@Singleton
@Component(
modules = {
RetrofitModule.class,
AppModule.class
})
public interface AppComponent {
AppComponent
提供具体 class 实现接口的方法应该如下所示:
@Singleton
@Module
public abstract class AppModule {
@Binds
public abstract NewsListModelContract provideNewsListModelContract(NewsListModelImp newsListModelImp);
}
NyTimesPresenter
的实现应该改变(只是用它实现的接口替换具体的 class):
public class NyTimesPresenter {
NewsListModelContract newsListModel;
@Inject
public NyTimesPresenter(NewsListModelContract newsListModel) {
this.newsListModel = newsListModel;
}
}