如何使用 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:你自己控制它。
我正在使用支持蓝牙(如果可用)的 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:你自己控制它。