刀柄注入不适用于 BroadcastReceiver

cmp*_*rog 15 android android-jetpack dagger-hilt

BroadcastReceiver使用 Hilt内部的依赖注入不起作用。我尝试BroadcastReceiver使用警报调用 aMainActivity并且我得到UninitializedPropertyAccessException. 根据文档,它应该像向@AndroidEntryPoint接收器添加注释一样简单,但不是。

示例代码:

应用程序.kt:

@HiltAndroidApp
class App: Application() {
    override fun onCreate() {
        super.onCreate()
        Log.d(App::class.simpleName, "onCreate: Application")
    }
}
Run Code Online (Sandbox Code Playgroud)

TestHiltInjection.kt:

class TestHiltInjection @Inject constructor() {

    operator fun invoke() {
        Log.d(TestHiltInjection::class.java.simpleName, "invoke called.")
    }
}
Run Code Online (Sandbox Code Playgroud)

HiltBroadcastReceiver.kt:

@AndroidEntryPoint
class HiltBroadcastReceiver : BroadcastReceiver() {

    @Inject lateinit var testHiltInjection: TestHiltInjection

    override fun onReceive(context: Context?, intent: Intent?) {
        testHiltInjection()
    }
}
Run Code Online (Sandbox Code Playgroud)

主活动.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
        )
    }
}
Run Code Online (Sandbox Code Playgroud)

输出日志:

kotlin.UninitializedPropertyAccessException: lateinit property testHiltInjection has not been initialized
Run Code Online (Sandbox Code Playgroud)

更新

问题已经在 2.29.1 版本解决,直接使用 @AndroidEntryPoint

Val*_*kov 28

更新:根据问题,问题应该在Dagger Hilt 2.29.1版本中修复。因此,只需使用 version2.29.1-alpha或更高版本。不要忘了更新hilt-android-gradle-plugin版本,以及


原始答案:存在 GitHub问题解决方法。似乎注入不起作用,因为它实际上发生在onReceive()生成的父类的方法内部。问题是你不能调用 super 方法,因为它是抽象的。但是你可以创建一个简单的包装类来解决这个问题:

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

    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 不错的发现!!我不敢相信谷歌在发布它之前没有捕获到它...... (3认同)

Sha*_*aon 6

使用 Hilt 的稳定版本。你可以轻松地注入任何这样的变量

@AndroidEntryPoint
public class SMSReceiver extends BroadcastReceiver {
    @Inject
    public DataManager dataManager;

    @Override
    public void onReceive(final Context context, Intent intent) {
    }
}
Run Code Online (Sandbox Code Playgroud)


Bek*_*Bek 5

我认为 hilt 目前不支持 BroadcastReceiver。在https://dagger.dev/hilt/android-entry-point 中

注意:Hilt 目前仅支持扩展 ComponentActivity 的 Activity 和扩展 androidx 库 Fragment 的 Fragment,不支持 Android 平台中的(现已弃用)Fragment。

内部工作原理:Hilt 为带@AndroidEntryPoint注释的组件(Activity、Fragment、BroadcastReceiver 等)创建抽象类,并且您的 BroadcastReceiver 将生成的类扩展为字节码转换中的基类。在基类onReceive方法中注入对象。但是在生成的字节码类onReceive中没有调用超类方法。这就是为什么你的对象没有被注入。testHiltInjection()HiltBroadcastReceiver课堂之前测试添加以下代码。顺便说一下,它仍然处于Alpha模式。

((HiltBroadcastReceiver_GeneratedInjector) BroadcastReceiverComponentManager.generatedComponent(context)).injectHiltBroadcastReceiver(UnsafeCasts.<HiltBroadcastReceiver>unsafeCast(this));
Run Code Online (Sandbox Code Playgroud)

更新:现在问题已在版本中修复2.29.1-alpha。也不要忘记将hilt-android-gradle-plugin版本升级到2.29.1-alpha或最新。有关版本的更多信息。

修复 #1918:通过 @AndroidEntryPoint 转换支持 BroadcastReceiver。(ede018b)