【问题标题】:What is the use case for @Binds vs @Provides annotation in Dagger2Dagger 2中@Binds和@Provides注解的用例是什么
【发布时间】:2018-10-01 08:07:57
【问题描述】:

我不确定 Dagger2 的@Bind annotation. 的目的

根据我在网上阅读的内容,我仍然不清楚,但这里有一个例子:

@Module
public abstract class HomeModule {

  @Binds
  public abstract HomePresenter bindHomePresenter(HomePresenterImp   
    homePresenterImp);
}

类定义如下所示:

public interface HomePresenter {
    Observable<List<User>> loadUsers();
}

public class HomePresenterImp implements HomePresenter {

    public HomePresenterImp(){
    }  

    @Override
    public Observable<List<User>> loadUsers(){
        //Return user list observable
    }
}

如果我可以使用提供注释,为什么我需要使用@Binds,如下所示:

@Provides
public HomePresenter provideHomePresenter() {
    return new HomePresenterImp();
}

@Binds 而不是 @Provides 的用例是什么?如果我使用@Binds,我还需要在我的应用组件中声明它吗(当我使用@Binds 时它是一个抽象类)?

【问题讨论】:

  • 如果你想将CustomActivity 绑定到AppCompatActivity,这只能使用Binds 注释来实现
  • @SamuelEminet 感谢您的回复。你能举一个例子,它是如何不能用提供来完成的,以及它是如何用绑定来完成的。我仍然很困惑,在这种情况下你有什么约束力?匕首是假设绑定依赖项,你为什么建议将 CustomActivity 绑定到 AppCompatActivity

标签: android dagger-2


【解决方案1】:

@Binds 可以完全等同于这样的@Provides-annotated 方法:

@Provides
public HomePresenter provideHomePresenter() {
    return new HomePresenterImp();
}

...尽管您可能更喜欢将 HomePresenterImp 作为方法参数的变体,它允许 Dagger 实例化 HomePresenterImp(假设它有一个 @Inject 构造函数),包括传递它需要的任何依赖项。您也可以将其设为static,因此 Dagger 无需实例化您的 Module 实例即可调用它。

@Provides
public static HomePresenter provideHomePresenter(HomePresenterImp presenter) {
    return presenter;
}

那你为什么要选择@Binds呢? Dagger has a FAQ about it,但归结为以下原因:

  • @Binds(稍微)更紧凑:您可以跳过实现。
  • @Binds 在接口和抽象类中工作,这是 @BindsOptionalOf 和 @ContributesAndroidInjector 等 Dagger 功能所严格要求的。
  • @Binds 帮助您的代码保持高效。 @Provides 方法可以是实例方法,这需要 Dagger 实例化您的 Module 才能调用它们。使您的@Provides 方法static 也可以完成此操作,但是如果您忘记了static,您的@Provides 方法仍然可以编译。 @Binds 方法不会。
  • @Binds 使 Dagger 不必为对象生成代码并为对象保留一个单独的工厂/提供程序,因为 Java 不会让 Dagger 访问知道实现就这么简单。在您的情况下,Dagger 可以将 Provider&lt;HomePresenterImp&gt; 转换为 Provider&lt;HomePresenter&gt; 并且只保留一个,而不是为 HomePresenter 保留一个,它只为 HomePresenterImp 调用一个。

因此,整个事情可以很好地表示为:

@Binds abstract HomePresenter bindHomePresenter(HomePresenterImp presenter);

【讨论】:

  • 嗨,你能举一个使用绑定注释的真实例子吗?
  • @j2emanue 你的意思是语法的例子吗?不难找到@Binds 的例子;它适用于任何接口/实现拆分。
  • 我想如果你给我一个真实世界的使用示例并将其与提供的产品进行比较可能会对我有所帮助。但是是的,如果不是,我可以继续搜索它只是一些在线示例仍然令人困惑,显然为什么我在这里哈哈。
  • @j2emanue:HomePresenterImp 是一个完美的真实示例。你不会找到一个明确的例子来说明@Binds 做某事@Provides 不能做,但在某些情况下@Binds 会更加简洁和高效。但是,如果您在使用抽象类或接口将其付诸实践时遇到问题,请check out this question 或发布一个新问题来说明您的进度。
【解决方案2】:

这是一个需要Bind 注释的具体案例,假设您有一个BaseActivityModule,它包含在所有提供活动视图模型的活动模块中。

@Module
object BaseActivityModule {
    @Provides
    @ActivityScope
    @ActivityContext
    @JvmStatic
    fun provideViewModelProvider(
        activity: AppCompatActivity,
        viewModelFactory: ViewModelProvider.Factory
    ): ViewModelProvider = ViewModelProviders.of(activity, viewModelFactory)
}

在这里您看到我们需要提供AppCompatActivityViewModelProvider.Factory。您不能为AppCompatActivity 提供Provide 注释,因为活动是由android 创建的。

我们假设您的具体 ActivityModule 例如 MainActivityModule 将提供 MainActivity 类,因为您创建了 MainActivity 子组件,或者您使用 ContributesAndroidInjector 自动创建子组件(但这是另一个话题) .

所以我们有我们的MainActivityModule 提供MainActivity 和我们的MainActivityModule 包括我们的BaseActivityModule 需要AppCompatActivity。所以这里是Bind 魔法,让我们告诉Dagger,当你需要AppCompatActivity 时,你可以使用我们的MainActivity

@Module(includes = [BaseActivityModule::class])
abstract class MainActivityModule {
    @Binds
    @ActivityScope
    abstract fun bindActivity(activity: MainActivity): AppCompatActivity
}

你可以从我的项目模板here看到更多

【讨论】:

  • 我在进一步考虑,你的意思是 Dagger 从注入调用中获取 MainActivity 引用并知道在我们使用 Binds 声明它时使用它吗?所以如果我调用 AndroidInjection.inject(this) (其中“this”是 MainActivity 的实例),它将在 BaseActivityModule 中使用相同的实例?
  • 感谢您的反馈。即使查看您的示例项目,特别是文件 ApplicationModule.kt(我看到您绑定 BeaverApplication),Dagger 是如何知道如何检索它的?我看到你有一个静态方法来获取应用程序 provideApplicationContext(...) 那么为什么在这种情况下你甚至需要绑定呢?
  • provideApplicationContext 确实可以通过绑定来完成:abstract fun bindApplicationContext(application: BeaverApplication): Context 通常,当您从传递的参数返回相同的实例时,您可以使用绑定而不是提供。并且绑定是强制性的,因为 dagger 只知道具体类,所以如果您使用接口或抽象类作为提供参数,您需要将这些接口/抽象的绑定添加到具体类
  • 您的回答具有误导性。你可以很容易地用@Provides 来表达后者,并且只需让bindActivity 返回它的参数activity。你是对的,你不想创建一个新的 Activity,但是提供的实现可以有任何逻辑,包括简单地返回它们的参数,这就是为什么 @Binds 不能做任何 @Provides 不能做的事情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
  • 2018-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多