如何使用 Dagger 2 BindsOptionalOf

How to use Dagger 2 BindsOptionalOf

我正在使用支持蓝牙(如果可用)的 Dagger 2 构建 Android 应用程序。我想用 Dagger 注入 BluetoothAdapter 依赖。

我知道一种用Dagger注入null值的方法,就是在Module中注解Provider方法,在Component中注解依赖声明,在注入处注解参数@Nullable.但是为了更清楚地表明 BluetoothAdapter 是一个 optional 依赖项(应用程序的其余部分也可以在没有 BT 的情况下工作,并且应该也可以在模拟器上工作),我想将依赖项声明为Optional<BluetoothAdapter> 描述为 in the official docs

我的模块中有一个 Provider 方法:

@Provides
static BluetoothAdapter providesBluetoothAdapter(MainApplication application) {
    ...
}

和组件中相应的声明:

BluetoothAdapter bluetoothAdapter();

按照说明,我将注入站点更改为 Optional<BluetoothAdapter>,使我的模块抽象化并在模块中添加了以下抽象方法:

@BindsOptionalOf abstract BluetoothAdapter optionalBluetoothAdapter();

然而,当在模拟器上 运行 时,它仍然失败并出现 java.lang.NullPointerException: Cannot return null from a non-@Nullable @Provides method 异常。 那时候我想,也许我误解了 @BindsOptionalOf 的目的,并从我的组件中删除了 BluetoothAdapter bluetoothAdapter(); 声明,看看它是否依赖于组件中是否声明了依赖项。还是不行。

我错过了什么?由于用 @BindsOptionalOf 注释的方法必须是抽象的,是否有可能完成我试图用可选绑定做的事情?

您没有按照预期的方式使用@BindsOptionalOf。 @BindsOptionalOf 最适合在编译时可能存在或不存在的绑定,因此最适合可重用模块。它不会帮助您判断运行时是否存在。

假设您正在构建一个可重用的库:

@Module public abstract class BluetoothAdapterModule {
  @Provides
  static BluetoothAdapter providesBluetoothAdapter(MainApplication application) {
    ...
  }
}

@Module public interface FooModule {
  // This consumes BluetoothAdapter when it happens to be present.
  @BindsOptionalOf BluetoothAdapter bindOptionalBluetoothAdapter();

  // Assume the Foo implementation injects Optional<BluetoothAdapter>.
  @Binds Bar bindBar(Foo foo);
}

这里,当FooModule和BluetoothAdapterModule绑定到同一个Component中时,就会有BluetoothAdapter的绑定。在您未包含 BluetoothAdapterModule 的不同组件或应用程序中,将不会绑定 BluetoothAdapter,如果您直接从 Foo(包括 @Nullable BluetoothAdapter)依赖 BluetoothAdapter,您的编译将失败。

然而,使用@BindsOptionalOf,你可以依靠 Dagger 来通知你你的 BluetoothAdapter 是否存在:你注入 Optional<BluetoothAdapter>。如果绑定可用,Optional 将是 "present" 并且 get 将是 return BluetoothAdapter;如果不可用,则 Optional 将为 "absent"。 (当然,如@BindsOptionalOf docs中所述,您还可以注入Optional<Provider<BluetoothAdapter>>Optional<Lazy<BluetoothAdapter>>等以进一步控制实例化对象的时间和位置。)

在这些情况下,@BindsOptionalOf 只需要向 Dagger 确认它应该管理该 Optional 实例的创建;否则,假设您犯了错误并忘记绑定您创建的 Optional 实例,它会抛出一个编译时异常。

为了反映蓝牙的存在与否仅在运行时已知,您需要使用@Nullable或您编写的单独的可注射BluetoothAdapterHolder .您还可以如上所述显式绑定 Optional<BluetoothAdapter>,使用符合您需要的存在或不存在特征显式创建它。那时,你不会使用 @BindsOptionalOf 因为你不依赖 Dagger 来反映 presence/absence:你自己控制它。