我正在使用Dagger2构建一个Android应用程序,如果可以的话,它支持蓝牙。我想用Dagger注入BluetoothAdapter依赖项。
我知道用dagger注入null
值的一种方法,即用@Nullable
注释模块中的provider方法、组件中的依赖声明和注入站点中的参数。但是为了更清楚地说明BluetoothAdapter是一个可选的依赖项(应用程序的其余部分也可以在没有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
注释的方法必须是抽象的,那么有可能完成我对可选绑定的尝试吗? 最佳答案
你用@bindsoptional的方式并不完全符合它的用途。@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();
@Binds Bar bindBar(Foo foo);
}
这里,当foomodule和bluetoothadaptermodule绑定到同一个组件中时,bluetoothadapter将有一个绑定,因此可以注入
Optional<BluetoothAdapter>
,并且get
将返回一个bluetoothadapter。在一个单独的组件中,如果您没有包含Bluetooth适配器模块,则Bluetooth适配器没有绑定。如果直接从foo(包括@Nullable BluetoothAdapter
)依赖bluetoothadapter,则编译将失败。但是,使用@BindsOptionalOf
,您可以依赖于Optional<BluetoothAdapter>
的注入,当包含Bluetooth适配器模块时,该模块存在,而当排除时则不存在。要在运行时反映蓝牙的存在或不存在,您需要使用
@Nullable
,或者编写一个单独的可注入的BluetoothAdapterHolder
。您还可以显式绑定Optional<BluetoothAdapter>
,并使用预期的存在或不存在特征显式创建它;此时,您不会使用@bindsoptionalof,因为您不依赖匕首来反映存在/不存在:您自己控制它。