我正在使用新的Dagger2(版本2.11),而且我正在使用AndroidInjector
和ContributesAndroidInjector
等新功能。我有一个活动子组件,
@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.
有没有办法做到这一点?
答案 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