有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Dagger2没有完全解决依赖关系

我有一个MainActivity,它注入Presenter,Presenter对象注入interactor,interactor对象注入APIHelper。演示者、交互者和APIHelper的所有提供者都在MainModule中

 @Module
public class MainActivityModule {
private final MainActivity activity;
//Context context;

public MainActivityModule (MainActivity activity) {
    this.activity = activity;
}



@Provides
@Singleton
public MainViewPresenter providesMainPresenter(){
    return new MainPresenterImpl(activity);
}

@Provides
@Singleton
ListingInteractor providesInteractor( ){
    return new ListingInteractorImpl(activity);
}

@Provides
@Singleton
ApiHelper providesAPI( ){
    return new ApiHelper(activity);
}

}

我已在MainActivity中注入组件,如:

DaggerMainActivityComponent.builder()
                .mainActivityModule(new MainActivityModule(MainActivity.this))
                .build().inject(this);

在我的Presenter实现中,我有一个类似interactor的:

public class MainPresenterImpl implements MainViewPresenter {
      Context context;
    private MainView mainView;
   // @Inject
    ListingInteractor interactor;  //here i get null interactor
    MyScrollListener scrollListener;

    public MainPresenterImpl(MainActivity activity) {

        this.context = activity;
        this.mainView = activity;
    }
    @Override
    public void getCatFacts() {
        interactor.getFacts();
    }

我的interactor实现类具有API帮助器,其构造函数需要上下文

public class ListingInteractorImpl implements ListingInteractor{
    private Context context;
    @Inject
    private APIHelper; // getting null APIHelper



    public ListingInteractorImpl(Context context) {
        this.context = context;

    } 

我的组件界面如下所示:

@Component(modules={MainActivityModule.class})
@Singleton
public interface MainActivityComponent {



    void inject(MainActivity mainActivity);

    /*void inject(MainPresenterImpl presenter);*/



    MainViewPresenter getMainPresenter();

    ListingInteractor getInteractor();

    ApiHelper getHelper();
}

但仅在MainActivity中创建presenter对象presenter中的所有其他对象(包括interactor、APIHelper)均为空。根据dagger的说法,它应该解决所有依赖关系


共 (2) 个答案

  1. # 1 楼答案

    匕首不是魔法。它不会神奇地将对象插入到任何你想要的地方,除非你告诉它这样做

    public class MainPresenterImpl implements MainViewPresenter {
      // ... other fields ...
      @Inject
      ListingInteractor interactor;
    
      public MainPresenterImpl(MainActivity activity) {
        this.context = activity;
        this.mainView = activity;
      }
    }
    

    匕首这是。。。没有什么您将一些字段(ListingInteractor)标记为字段注入,但除非手动调用组件来注入对象,否则不会发生任何事情。字段注入应该为不能向构造函数添加参数的活动和片段保留,而不是为普通类保留

    @Provides
    @Singleton
    MainViewPresenter providesMainPresenter(){
      return new MainPresenterImpl(activity);
    }
    

    与其让Dagger为您创建MainPresenterImpl,不如自己调用new MainPresenterImpl(),只传递活动。因为没有对MainPresenterImpl.interactor的调用,所以它将是null。您没有使用字段注入,您自己调用构造函数,也没有分配字段
    在模块中手动创建对象应保留给需要进一步设置的对象,如RetrofitOkHttp及其构建器

    如果您想设置字段,可以使用字段注入,将对象注册到组件(那些inject(FieldInjectableClass clazz)方法)中,并在代码中散布component.inject(myObject),这将是一个非常糟糕的主意,因为您最终会编写大量不需要的样板文件

    更合理的方法是将依赖项移动到它们所属的构造函数

    public MainPresenterImpl(MainActivity activity, ListingInteractor interactor) { /* ... */ }
    

    如果您依赖于另一个类,为什么不声明它呢?但这仍然留下了你自己创建对象的样板,而不是让Dagger完成它的工作

    这就是为什么您应该使用构造函数注入。顾名思义,它是关于构造函数的。只需添加@Inject注释:

    @Inject // marked for constructor injection!
    public MainPresenterImpl(MainActivity activity, ListingInteractor interactor) { /* ... */ }
    

    现在Dagger知道你的类的这个入口点,并且可以创建它

    要让dagger处理事情,您可以将@Singleton作用域添加到类本身(注释类,而不是构造函数),然后删除它的@Provides方法(不需要在模块中为不需要进一步设置的对象提供方法),但是,由于要将实现绑定到接口,因此仍然需要指定要绑定到接口的类

    @Provides
    @Singleton
    MainViewPresenter providesMainPresenter(MainPresenterImpl implementation){
      return implementation;
    }
    

    因为Dagger可以通过构造函数注入创建MainPresenterImpl,所以您可以返回接口的实现,并且在构造函数签名更改的情况下不需要更新任何代码,因为Dagger只会相应地调整类实例化

    这就是如何使用构造函数注入并将实现绑定到接口。如前所述,我强烈建议大家阅读基础知识。确保你们了解匕首的作用和工作原理。确保知道字段注入和构造函数注入之间的区别,或者何时使用模块

    您现在在学习Dagger上投入的时间将意味着以后调试和错误将大大减少


    如果您的模块是抽象的或接口,您也可以使用@Binds方法,Dagger将只生成上面的样板代码

    @Binds
    @Singleton
    MainViewPresenter providesMainPresenter(MainPresenterImpl implementation);
    
  2. # 2 楼答案

    更改MainPresenterImpl&ListingInteractorImpl构造函数以@Inject开头并跟随它们:

    
        @Inject
        public MainPresenterImpl(MainActivity activity, ListingInteractor interactor) {...}
    
        @Inject
        public ListingInteractorImpl(Context context, APIHelper helper) {...}
    
    

    然后在模块实现中:

    
        @Provides
        @Singleton
        public MainViewPresenter providesMainPresenter(ListingInteractor interactor){
            return new MainPresenterImpl(activity, interactor);
        }
    
        @Provides
        @Singleton
        ListingInteractor providesInteractor(APIHelper helper){
            return new ListingInteractorImpl(activity, helper);
        }