Hilt Injection not working with BroadcastReceiver

跟風遠走 提交于 2021-01-26 04:01:23

问题


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

  1. create new EntryPoint

    @EntryPoint
    @InstallIn(ApplicationComponent::class)
    interface MyEntryPoint {
        fun getSomeModule: SomeModule
    }
    
  2. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!