Android Service类能否用构造注入?首次启动崩溃二次启动正常的原因
问题根本原因及解决方案
核心原因分析
1. Android系统实例化Service的强制要求
FirebaseMessagingService属于Android系统托管的组件,系统会在特定场景(比如应用首次启动、首次接收FCM推送)通过反射机制创建其实例,而反射创建的前提是类必须提供无参构造函数。你的MyFirebaseMessagingService仅定义了带@Inject注解的有参构造,完全没有无参构造,这就违反了系统的实例化规则,首次启动时系统直接反射失败抛出InstantiationException。
2. 二次启动正常的原因
首次崩溃会导致应用进程重启,此时你的依赖注入框架(比如Dagger)已经完成了全局组件的初始化,并且通过框架的Android扩展能力(比如Dagger Android的AndroidInjection)接管了Service的实例创建流程。当系统再次尝试获取MyFirebaseMessagingService实例时,会使用DI框架提供的已注入依赖的实例,而非自己通过反射创建,因此不会再触发无参构造的问题。
解决方案
要同时满足系统的实例化要求和依赖注入需求,正确的做法是:
- 为
MyFirebaseMessagingService添加无参构造函数,供系统反射调用; - 使用字段注入替代构造注入,并在
onCreate方法中手动触发依赖注入。
示例代码:
class MyFirebaseMessagingService : FirebaseMessagingService() { // 用lateinit修饰字段,等待注入 @Inject lateinit var repository: Repository // 必须保留无参构造,供系统反射实例化 constructor() : super() override fun onCreate() { super.onCreate() // 触发依赖注入,由DI框架完成repository的初始化 AndroidInjection.inject(this) } // 业务逻辑代码... }
如果坚持使用构造注入,也可以保留带@Inject的有参构造,但必须同时提供无参构造(不过这种硬编码组件创建的方式不推荐,易引发生命周期不一致问题):
class MyFirebaseMessagingService @Inject constructor(private val repository: Repository) : FirebaseMessagingService() { // 无参构造,委托给有参构造 constructor() : this(DaggerAppComponent.create().repository) // 业务逻辑代码... }
内容的提问来源于stack exchange,提问作者Ashish Gautam
相关产品推荐
相关产品推荐

