如何在Hilt中使用Dagger的Provider<T>接口?
在Hilt中使用Dagger Provider实现异步单例初始化
要在Hilt中借助Provider<T>实现类的非主线程异步初始化并保证单例,核心思路是利用Provider<T>延迟实例创建时机,再通过后台线程触发初始化并控制单例唯一性,具体步骤如下:
1. 定义目标初始化类
确保你的耗时初始化类具备@Inject构造函数(或在Hilt模块中提供绑定),让Hilt能为其生成Provider<T>:
class HeavySdkClient @Inject constructor() { init { // 模拟耗时初始化操作(如加载配置、连接服务) Thread.sleep(2000) } fun executeBusinessLogic() { // 业务方法 } }
2. 注入Provider<T>而非直接注入实例
在负责异步初始化的单例管理器中,注入Provider<HeavySdkClient>,而非直接注入HeavySdkClient——这样Hilt不会在依赖注入阶段提前初始化该类,仅在调用Provider.get()时才触发实例创建:
@Singleton class SdkInitializer @Inject constructor( private val sdkProvider: Provider<HeavySdkClient> ) { private var initializedSdk: HeavySdkClient? = null private val lock = Any() // 异步获取实例,回调返回结果 fun getSdkAsync(callback: (HeavySdkClient) -> Unit) { // 已初始化直接返回 initializedSdk?.let { callback(it) return } // 双重校验锁保证仅初始化一次 synchronized(lock) { initializedSdk?.let { callback(it) return } // 后台线程执行初始化 CoroutineScope(Dispatchers.IO).launch { val sdkInstance = sdkProvider.get() synchronized(lock) { initializedSdk = sdkInstance } // 回到主线程回调结果(可选,根据业务需求调整) withContext(Dispatchers.Main) { callback(sdkInstance) } } } } // 或用Flow返回实例(更贴合Kotlin协程生态) fun getSdkFlow(): Flow<HeavySdkClient> = flow { initializedSdk?.let { emit(it) return@flow } synchronized(lock) { initializedSdk?.let { emit(it) return@flow } val sdkInstance = sdkProvider.get() initializedSdk = sdkInstance emit(sdkInstance) } }.flowOn(Dispatchers.IO) }
3. 在业务代码中使用异步初始化的实例
在ViewModel、Activity等组件中注入SdkInitializer,通过它获取初始化完成的实例:
@HiltViewModel class MainViewModel @Inject constructor( private val sdkInitializer: SdkInitializer ) : ViewModel() { fun useSdk() { // 回调方式 sdkInitializer.getSdkAsync { sdk -> sdk.executeBusinessLogic() } // Flow方式(推荐,适配生命周期) viewModelScope.launch { sdkInitializer.getSdkFlow().collect { sdk -> sdk.executeBusinessLogic() } } } }
关键注意事项
- 如果目标类本身需要全局单例,可以在Hilt模块中为其添加
@Singleton绑定:
此时@Module @InstallIn(SingletonComponent::class) object AppModule { @Provides @Singleton fun provideHeavySdkClient(): HeavySdkClient { return HeavySdkClient() } }Provider.get()会始终返回同一个单例实例,首次调用时的初始化仍在后台线程执行。 - 避免直接在主线程调用
Provider.get(),否则会阻塞UI,必须通过后台线程触发。
内容的提问来源于stack exchange,提问作者me.at.coding
相关产品推荐
相关产品推荐

