Dagger2:如何在同一个模块中使用@Provides和@Binds

时间:2017-10-07 09:42:08

标签: android dagger-2

我正在使用新的Dagger2(版本2.11),而且我正在使用AndroidInjectorContributesAndroidInjector等新功能。我有一个活动子组件,

        @Module
        abstract class ActivityBuilderModule {
            @ContributesAndroidInjector(modules = 
                   {UserListModule.class, MainFragmentModule.class})
            @ActivityScope
            abstract MainActivity bindsMainActivity();

        }



  @Module
  public abstract class MainFragmentModule {
    @ContributesAndroidInjector
    @FragmentScope
    @FragmentKey(UserListFragment.class)
    abstract UserListFragment bindsUserListFragment();

}

UserListModule提供片段的依赖关系。一些依赖项我只想绑定实例,并返回,如

 @Binds
 @ActivityScope
 abstract UserListView mUserListView(UserListFragment userListFragment);

而不仅仅是返回依赖关系,比如

@Provides
@ActivityScope
UserListView mUserListView(UserListFragment userListFragment){
    return userListFragment;
}

我的模块也包含一些@Provides方法。我们可以在同一个模块中同时使用@Binds@Provides方法吗?我试过如下所示

        @Module
        public abstract class UserListModule {
            @Provides
            @ActivityScope
            UserListFragment mUserListFragment() {
                return new UserListFragment();
            }

            @Binds
            @ActivityScope
            abstract UserListView mUserListView(UserListFragment userListFragment);

           // other provides and binds methods...
           ......
           .....

        }

它的投掷错误

Error:(22, 8) error: dagger.internal.codegen.ComponentProcessor was unable to process this interface because not all of its dependencies could be resolved. Check for compilation errors or a circular dependency with generated code.

有没有办法做到这一点?

4 个答案:

答案 0 :(得分:21)

@Binds@ContributesAndroidInjector方法必须是抽象的,因为它们没有方法体。这意味着他们必须继续使用接口或抽象类。 @Provides方法可能是static,这意味着它们可以继续使用抽象类和Java-8编译的接口,但非静态(“实例”)@Provides方法不起作用抽象类。这在Dagger常见问题解答中明确列在"Why can’t @Binds and instance @Provides methods go in the same module?""What do I do instead?"部分下。

如果您的@Provides方法不使用实例状态,则可以将其标记为static,并且它可以转到与您的@Binds方法相邻的抽象类。如果没有,请考虑将@Binds@ContributesAndroidInjector之类的绑定放入一个单独的类 - 可能是静态嵌套类 - 并使用Dagger includes上的@Module属性包含该类注释

答案 1 :(得分:7)

对上述Jeff的解决方案做了一些补充:

您可以创建内部接口,而不是静态内部类,如下所示:

@Module(includes = AppModule.BindsModule.class)
public class AppModule {
    // usual non-static @Provides
    @Provides
    @Singleton
    Checkout provideCheckout(Billing billing, Products products) {
        return Checkout.forApplication(billing, products);
    }
    // interface with @Binds
    @Module
    public interface BindsModule {
        @Binds
        ISettings bindSettings(Settings settings);
    }
}

答案 2 :(得分:4)

如果您身处科特林世界,另一种选择是利用func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "customCellID", for: indexPath) as! CustomTableCell cell.accessoryView = UIImageView(image: "imageName") // This is where the magic happens cell.accessoryView?.bounds = CGRect(x: 0, y: 0, width: 50, height: 50) return cell }

companion object

答案 3 :(得分:0)

这是另一种类型的解决方案:将模块添加到其他模块之后,您可以在组件界面中调用顶级模块。因为可以使用抽象和静态方法,所以它可以提高效率。

详细信息和示例如下:

例如,我们有一个组件接口和两个模块,例如 ComponentClasses Module_ClassA Module_ClassB

Module_ClassA 是:

@Module
public class Module_ClassA {

   @Provides
   static ClassA provideClassA(){

     return new ClassA();
   }
}

Module_ClassB 是:

@Module
abstract class Module_ClassB {

   @Binds
   abstract ClassB bindClassB(Fragment fragment); //Example parameter
}

现在,我们有两个模型。如果要一起使用它们,则可以将其中一个添加到另一个。例如:您可以将 Module_ClassB 添加到 Module_ClassA

@Module(includes = Module_ClassB.class)
public class Module_ClassA {

   @Provides
   static ClassA provideClassA(){

     return new ClassA();
   }
}

最后,您不需要将两个模块都添加到组件类中。您只能将顶层模块添加到组件类中,如下所示:

ComponentClasses 是:

@Component(modules = Module_ClassA)
public interface ComponentClasses {

   //Example code 
   ArrayList<CustomModel> getList();

}

但是,您应该小心,因为您需要添加顶部模块。因此,在ComponentClasses接口上添加了Module_ClassA。

@canerkaseler