我正在尝试创建第一款Android Dagger应用。 我已经阅读了一些教程,现在我正在尝试使它工作。 问题是,当我在MainActivity中调用settings.get()时,我得到了
java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object javax.inject.Provider.get()' on a null object reference
at biz.golek.whattodofordinner.MainActivity.onOptionsItemSelected(MainActivity.java:57)
是: 的 settings.get()执行命令();
我创建了:
MainActivity:
public class MainActivity extends AppCompatActivity {
@Inject
Provider<ShowSettingsController> settings;
/.../
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
settings.get().Run();
return true;
}
return super.onOptionsItemSelected(item);
}
}
应用:
public class WhatToDoForDinnerApp extends com.orm.SugarApp {
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new ActivityInjector());
}
}
ActivityInjector:
public class ActivityInjector implements Application.ActivityLifecycleCallbacks {
private ApplicationComponent component;
public ActivityInjector(){
this.component = DaggerApplicationComponent.builder()
.settingsModule(new SettingsModule())
.build();
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
component.inject(activity);
}
/.../
}
ApplicationComponent:
@Singleton
@Component(modules = { SettingsModule.class })
public interface ApplicationComponent {
void inject(Activity activity);
}
和SettingsModule:
@Module
public class SettingsModule {
@Provides
@Singleton
static ShowSettingsController provideShowSettingsController(){
return new ShowSettingsControllerImpl();
}
/.../
}
整个代码在我的github:whattodofordinner Aby想法我错了什么? 提前谢谢。
答案 0 :(得分:1)
我认为在您的ApplicationComponent
中,您必须为每个活动定义inject
- 方法。不可能使用组合物。
@Singleton
@Component(modules = { SettingsModule.class })
public interface ApplicationComponent {
void inject(MainActivity activity);
void inject(AnotherActivity activity);
}
编辑04.02.16:
此外,您的provide-method是静态声明的。尝试删除该静态。
@Module
public class SettingsModule {
@Provides
@Singleton
ShowSettingsController provideShowSettingsController(){
return new ShowSettingsControllerImpl();
}
/.../
}
您也可以在ApplicationComponent中声明一个provide语句:
@Singleton
@Component(modules = { SettingsModule.class })
public interface ApplicationComponent {
SettingsController settingsController();
void inject(MainActivity activity);
void inject(AnotherActivity activity);
}
答案 1 :(得分:0)
您似乎错过了ApplicationComponent中的SettingsModule。如果您确实希望设置模块在整个应用程序的范围内可用,那么将其添加到模块列表中,如下所示:
@Singleton
@Component(modules = { AppModule.class, SettingsModule.class })
public interface ApplicationComponent {
void inject(Activity activity);
}
你的ActivityInjector也必须像这样更新:
public class ActivityInjector implements Application.ActivityLifecycleCallbacks {
private ApplicationComponent component;
public ActivityInjector(){
this.component = DaggerApplicationComponent.builder()
.appModule(new AppModule())
.settingsModule(new SettingsModule())
.build();
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
component.inject(activity);
}
/.../
答案 2 :(得分:0)
我已经完成了这项工作。不知道为什么,但Dagger不想按字段注入依赖项,但使用构造函数完美地工作。 IMO使用构造函数甚至更好(依赖关系通过构造函数参数显示),所以我已经改变了我的类以使用注入的构造函数。
第二件事是如何在不知道容器(组件)的情况下将依赖项放入Activity。
我是通过定义IAware接口来实现的:
public interface IAware<T> {
void Set(T item);
}
然后标记接口IControllersProviderAware:
public interface IControllersProviderAware extends IAware<ControllersProvider> {
}
ControllersProvider类也不知道容器,它只知道javax.inject,因为使用了Provider类,但它是通用的,不依赖于Dagger(容器特定的实现):
public class ControllersProvider {
private final Provider<ShowSettingsController> showSettingsControllerProvider;
public ControllersProvider(Provider<ShowSettingsController> showSettingsControllerProvider)
{
this.showSettingsControllerProvider = showSettingsControllerProvider;
}
public ShowSettingsController getShowSettingsController() {
return showSettingsControllerProvider.get();
}
}
最后要做的是ControllersProviderInjector的实现,如果活动知道ControllersProvider,它负责将ControllersProvider设置为活动:
public class ControllersProviderInjector implements Application.ActivityLifecycleCallbacks {
private ControllersProvider controllersProvider;
@Inject
public ControllersProviderInjector(ControllersProvider controllersProvider) {
this.controllersProvider = controllersProvider;
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
if (activity instanceof IControllersProviderAware)
((IControllersProviderAware)activity).Set(controllersProvider);
}
}
Everythig在模块中注册:
@Module
public class AppModule {
@Provides
@Singleton
static ControllersProvider provideControllersProvider(
Provider<ShowSettingsController> showSettingsControllerProvider
){
return new ControllersProvider(
showSettingsControllerProvider
);
}
}
最后执行Activity:
public class MainActivity extends AppCompatActivity implements IControllersProviderAware {
private ControllersProvider controllerProvider;
/.../
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
this.controllerProvider.getShowSettingsController().Run();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void Set(ControllersProvider item) {
this.controllerProvider = item;
}
}
执行此“并发症”而不是将getComponent方法添加到App,并从onCreate of Activity(如图所示here使用它)的主要优点是业务逻辑与容器细节的独立性。当有更好的容器而不是匕首时,为了改变它,我可以简单地改变我的ControllersProvider和容器特定的东西的实现。
一切都在我的github上:https://github.com/bartoszgolek/whattodofordinner
感谢大家的帮助,希望你能享受我的工作。
答案 3 :(得分:0)
我在github上查看了你的项目,并注意到使用dagger框架的一些误解。我做了几个修复和依赖注入很好。
首先,您需要使您的依赖图可用于其他应用程序组件。
public class WhatToDoForDinnerApp extends com.orm.SugarApp {
private ApplicationComponent component;
public ApplicationComponent getComponent() {
return component;
}
@Override
public void onCreate() {
super.onCreate();
component = DaggerApplicationComponent.builder()
.appModule(new AppModule())
.settingsModule(new SettingsModule())
.addNewDinnerModule(new AddNewDinnerModule())
.build();
...
}
}
然后你需要告诉匕首什么类期望注射。
@Singleton
@Component(modules = {AppModule.class, SettingsModule.class, AddNewDinnerModule.class})
public interface ApplicationComponent {
ViewStateManager viewStateManager();
ControllersProviderInjector controllersProviderInjector();
void inject(MainActivity activity); //now you are able to inject dependencies in your MainActivity
}
最后你需要注入你需要的东西。在这种情况下,您可以注入AppModule
中声明的所有模块(SettingsModule
,AddNewDinnerModule
,ApplicationComponent
)提供的所有项目。
public class MainActivity extends AppCompatActivity {
private View.OnClickListener listener;
@Inject
Provider<ShowSettingsController> showSettingsController;
@Inject
Provider<AddNewDinnerController> newDinnerController;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((WhatToDoForDinnerApp) getApplication()).getComponent().inject(this); //at this moment your dependencies are injected
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(...);
listener = new View.OnClickListener() {
@Override
public void onClick(View view) {
newDinnerController.get().Run();
}
};
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
...
if (id == R.id.action_settings) {
showSettingsController.get().Run();
return true;
}
...
}