Hilt 注入不适用于 BroadcastReceiver
Hilt Injection not working with BroadcastReceiver
BroadcastReceiver
中使用 Hilt 的依赖项注入不起作用。我尝试使用来自 MainActivity
的警报调用 BroadcastReceiver
,我得到 UninitializedPropertyAccessException
。根据文档,它应该像向接收器添加 @AndroidEntryPoint
注释一样简单,但事实并非如此。
示例代码:
App.kt:
@HiltAndroidApp
class App: Application() {
override fun onCreate() {
super.onCreate()
Log.d(App::class.simpleName, "onCreate: Application")
}
}
TestHiltInjection.kt:
class TestHiltInjection @Inject constructor() {
operator fun invoke() {
Log.d(TestHiltInjection::class.java.simpleName, "invoke called.")
}
}
HiltBroadcastReceiver.kt:
@AndroidEntryPoint
class HiltBroadcastReceiver : BroadcastReceiver() {
@Inject lateinit var testHiltInjection: TestHiltInjection
override fun onReceive(context: Context?, intent: Intent?) {
testHiltInjection()
}
}
MainActivity.kt:
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val manager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val pending = PendingIntent
.getBroadcast(this, 0, Intent(this, HiltBroadcastReceiver::class.java), 0)
manager.setInexactRepeating(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
15000, 15000,
pending
)
}
}
输出Logcat:
kotlin.UninitializedPropertyAccessException: lateinit property testHiltInjection has not been initialized
更新
问题已经在2.29.1版本上解决,只需使用@AndroidEntryPoint
我认为 hilt 目前不支持 BroadcastReceiver。在 https://dagger.dev/hilt/android-entry-point 中说
Note: Hilt currently only supports activities that extend ComponentActivity and fragments that extend androidx library Fragment, not the (now deprecated) Fragment in the Android platform.
内部工作原理:Hilt 为 @AndroidEntryPoint
注释组件(Activity、Fragment、BroadcastReceiver 等)创建抽象 class 并且您的 BroadcastReceiver 扩展生成的 class 作为基础class 在字节码转换中。在 base class onReceive
方法中注入对象。但是在生成的字节码中 class super class onReceive
方法没有被调用。这就是为什么你的对象没有被注入。
要测试在 HiltBroadcastReceiver
class 中的 testHiltInjection()
之前添加以下代码。顺便说一下,它仍处于 Alpha 模式。
((HiltBroadcastReceiver_GeneratedInjector) BroadcastReceiverComponentManager.generatedComponent(context)).injectHiltBroadcastReceiver(UnsafeCasts.<HiltBroadcastReceiver>unsafeCast(this));
更新: 现在问题已在版本 2.29.1-alpha
中修复。也不要忘记将 hilt-android-gradle-plugin
版本升级到 2.29.1-alpha
或最新版本。有关 releases 的更多信息。
Fix #1918: Support BroadcastReceiver with @AndroidEntryPoint transform. (ede018b)
更新: 根据issue the problem should be fixed in version 2.29.1 of Dagger Hilt. So, just use version 2.29.1-alpha
or above. Don't forget to update hilt-android-gradle-plugin
version as well.
原回答:有个GitHubissue and a workaround。似乎注入不起作用,因为它实际上发生在生成的父 class 的 onReceive()
方法内部。问题是你不能调用 super 方法,因为它是抽象的。但是您可以创建一个简单的包装器 class 来解决问题:
abstract class HiltBroadcastReceiver : BroadcastReceiver() {
@CallSuper
override fun onReceive(context: Context, intent: Intent) {}
}
@AndroidEntryPoint
class MyBroadcastReceiver : HiltBroadcastReceiver() {
@Inject lateinit var testHiltInjection: TestHiltInjection
override fun onReceive(context: Context?, intent: Intent?) {
super.onReceive(context, intent) // <-- it's the trick
...
}
}
目前,由于 Hilt 错误,您无法将 @AndroidEntryPoint
用于 BroadcastReceiver。
相反,您使用这样的变通逻辑
如果你想在 BroadcastReceiver 中注入 SomeModule
创建新入口点
@EntryPoint
@InstallIn(ApplicationComponent::class)
interface MyEntryPoint {
fun getSomeModule: SomeModule
}
获取入口点并使用它
class MyBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val someModule : SomeModule =
EntryPoints.get(context?.applicationContext, MyEntryPoint::class.java)
.getSomeModule()
}
}
使用稳定版的 Hilt。你可以像这样轻松地注入任何变量
@AndroidEntryPoint
public class SMSReceiver extends BroadcastReceiver {
@Inject
public DataManager dataManager;
@Override
public void onReceive(final Context context, Intent intent) {
}
}
Hilt 现已稳定。现在很简单:
@AndroidEntryPoint
class MyAppWidget : AppWidgetProvider() {
@Inject
lateinit var getMyUseCase: MyUseCase
BroadcastReceiver
中使用 Hilt 的依赖项注入不起作用。我尝试使用来自 MainActivity
的警报调用 BroadcastReceiver
,我得到 UninitializedPropertyAccessException
。根据文档,它应该像向接收器添加 @AndroidEntryPoint
注释一样简单,但事实并非如此。
示例代码:
App.kt:
@HiltAndroidApp
class App: Application() {
override fun onCreate() {
super.onCreate()
Log.d(App::class.simpleName, "onCreate: Application")
}
}
TestHiltInjection.kt:
class TestHiltInjection @Inject constructor() {
operator fun invoke() {
Log.d(TestHiltInjection::class.java.simpleName, "invoke called.")
}
}
HiltBroadcastReceiver.kt:
@AndroidEntryPoint
class HiltBroadcastReceiver : BroadcastReceiver() {
@Inject lateinit var testHiltInjection: TestHiltInjection
override fun onReceive(context: Context?, intent: Intent?) {
testHiltInjection()
}
}
MainActivity.kt:
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val manager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val pending = PendingIntent
.getBroadcast(this, 0, Intent(this, HiltBroadcastReceiver::class.java), 0)
manager.setInexactRepeating(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
15000, 15000,
pending
)
}
}
输出Logcat:
kotlin.UninitializedPropertyAccessException: lateinit property testHiltInjection has not been initialized
更新
问题已经在2.29.1版本上解决,只需使用@AndroidEntryPoint
我认为 hilt 目前不支持 BroadcastReceiver。在 https://dagger.dev/hilt/android-entry-point 中说
Note: Hilt currently only supports activities that extend ComponentActivity and fragments that extend androidx library Fragment, not the (now deprecated) Fragment in the Android platform.
内部工作原理:Hilt 为 @AndroidEntryPoint
注释组件(Activity、Fragment、BroadcastReceiver 等)创建抽象 class 并且您的 BroadcastReceiver 扩展生成的 class 作为基础class 在字节码转换中。在 base class onReceive
方法中注入对象。但是在生成的字节码中 class super class onReceive
方法没有被调用。这就是为什么你的对象没有被注入。
要测试在 HiltBroadcastReceiver
class 中的 testHiltInjection()
之前添加以下代码。顺便说一下,它仍处于 Alpha 模式。
((HiltBroadcastReceiver_GeneratedInjector) BroadcastReceiverComponentManager.generatedComponent(context)).injectHiltBroadcastReceiver(UnsafeCasts.<HiltBroadcastReceiver>unsafeCast(this));
更新: 现在问题已在版本 2.29.1-alpha
中修复。也不要忘记将 hilt-android-gradle-plugin
版本升级到 2.29.1-alpha
或最新版本。有关 releases 的更多信息。
Fix #1918: Support BroadcastReceiver with @AndroidEntryPoint transform. (ede018b)
更新: 根据issue the problem should be fixed in version 2.29.1 of Dagger Hilt. So, just use version 2.29.1-alpha
or above. Don't forget to update hilt-android-gradle-plugin
version as well.
原回答:有个GitHubissue and a workaround。似乎注入不起作用,因为它实际上发生在生成的父 class 的 onReceive()
方法内部。问题是你不能调用 super 方法,因为它是抽象的。但是您可以创建一个简单的包装器 class 来解决问题:
abstract class HiltBroadcastReceiver : BroadcastReceiver() {
@CallSuper
override fun onReceive(context: Context, intent: Intent) {}
}
@AndroidEntryPoint
class MyBroadcastReceiver : HiltBroadcastReceiver() {
@Inject lateinit var testHiltInjection: TestHiltInjection
override fun onReceive(context: Context?, intent: Intent?) {
super.onReceive(context, intent) // <-- it's the trick
...
}
}
目前,由于 Hilt 错误,您无法将 @AndroidEntryPoint
用于 BroadcastReceiver。
相反,您使用这样的变通逻辑
如果你想在 BroadcastReceiver 中注入 SomeModule
创建新入口点
@EntryPoint @InstallIn(ApplicationComponent::class) interface MyEntryPoint { fun getSomeModule: SomeModule }
获取入口点并使用它
class MyBroadcastReceiver : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { val someModule : SomeModule = EntryPoints.get(context?.applicationContext, MyEntryPoint::class.java) .getSomeModule() } }
使用稳定版的 Hilt。你可以像这样轻松地注入任何变量
@AndroidEntryPoint
public class SMSReceiver extends BroadcastReceiver {
@Inject
public DataManager dataManager;
@Override
public void onReceive(final Context context, Intent intent) {
}
}
Hilt 现已稳定。现在很简单:
@AndroidEntryPoint
class MyAppWidget : AppWidgetProvider() {
@Inject
lateinit var getMyUseCase: MyUseCase