问题
Dependency injection inside BroadcastReceiver
using Hilt isn't working. I try to invoke a BroadcastReceiver
using an alarm from MainActivity
and i am getting UninitializedPropertyAccessException
. According to the documentation it should be as simple as adding the @AndroidEntryPoint
annotation to the receiver but its not.
Sample Code:
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
)
}
}
Output Logcat:
kotlin.UninitializedPropertyAccessException: lateinit property testHiltInjection has not been initialized
Update
Issue was already solved on 2.29.1 version, just use @AndroidEntryPoint
回答1:
Update: According to the 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.
Original answer: There's a GitHub issue and a workaround. It seems that injection doesn't work because it actually happens inside onReceive()
method of the generated parent class. The problem is that you cannot call the super method since it's abstract. But you can create a simple wrapper class that fixes the problem:
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
...
}
}
回答2:
I think hilt currently doesn't support BroadcastReceiver. In https://dagger.dev/hilt/android-entry-point says
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.
How it works internally: Hilt creates abstract class for @AndroidEntryPoint
annotated component(Activity, Fragment, BroadcastReceiver etc) and your BroadcastReceiver extends generated class as base class in bytecode transformation. In base class onReceive
method object is injected. But in generated bytecode class super class onReceive
method is not called. That's why your object is not injected.
To test add below code before testHiltInjection()
in HiltBroadcastReceiver
class. By the way it's still in Alpha mode.
((HiltBroadcastReceiver_GeneratedInjector) BroadcastReceiverComponentManager.generatedComponent(context)).injectHiltBroadcastReceiver(UnsafeCasts.<HiltBroadcastReceiver>unsafeCast(this));
Update: Now issue has been fixed in version 2.29.1-alpha
. Also do not forget to upgrade hilt-android-gradle-plugin
version to 2.29.1-alpha
or latest. More info on releases .
Fix #1918: Support BroadcastReceiver with @AndroidEntryPoint transform. (ede018b)
回答3:
Currently, you can't use @AndroidEntryPoint
for BroadcastReceiver due to Hilt bug.
instead you use workaround logic like this
if you want to inject SomeModule in BroadcastReceiver
create new EntryPoint
@EntryPoint @InstallIn(ApplicationComponent::class) interface MyEntryPoint { fun getSomeModule: SomeModule }
get entrypoint and use it
class MyBroadcastReceiver : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { val someModule : SomeModule = EntryPoints.get(context?.applicationContext, MyEntryPoint::class.java) .getSomeModule() } }
来源:https://stackoverflow.com/questions/62335727/hilt-injection-not-working-with-broadcastreceiver