如何通过Dagger注入DynamoDBMapper并适配AWSMobileClient初始化?
解决Dagger注入DynamoDBMapper时因AWSMobileClient未初始化导致的崩溃问题
这个问题的核心在于AWSMobileClient的初始化是异步操作,而Dagger会在应用启动阶段就尝试创建单例依赖(比如你的AmazonDynamoDBClient和DynamoDBMapper),这时候AWSMobileClient还没完成初始化,导致凭证提供者为空,最终引发崩溃。下面给你几个可行的解决方案:
方案一:等待AWSMobileClient初始化完成后再初始化Dagger组件
最直接的方式是确保Dagger组件在AWSMobileClient初始化完成后再创建。你可以在Application类中调整初始化顺序:
class MyApplication : Application() { lateinit var appComponent: AppComponent override fun onCreate() { super.onCreate() // 先初始化AWSMobileClient,回调中创建Dagger组件 AWSMobileClient.getInstance().initialize(this) { userState -> Timber.d("AWSMobileClient initialized successfully, state: ${userState.userState}") // 初始化Dagger组件 appComponent = DaggerAppComponent.create() // 这里可以通过LiveData或EventBus通知UI层Dagger已就绪 }.execute() } }
之后在Activity/Fragment中,需要确保appComponent已经初始化完成再使用(比如添加启动页显示加载状态,或者用LiveData监听初始化完成事件)。这种方式能彻底避免Dagger提前创建依赖的问题。
方案二:封装AWSMobileClient为可等待的单例
创建一个包装类,把AWSMobileClient的异步初始化转为可挂起的操作,确保依赖它的组件能等待初始化完成:
class AWSMobileClientManager private constructor() { lateinit var client: AWSMobileClient private val initDeferred = CompletableDeferred<Unit>() suspend fun initialize(context: Context) { if (!::client.isInitialized) { val callback = object : Callback<UserStateDetails> { override fun onResult(result: UserStateDetails?) { client = AWSMobileClient.getInstance() initDeferred.complete(Unit) } override fun onError(e: Exception?) { initDeferred.completeExceptionally(e!!) } } AWSMobileClient.getInstance().initialize(context, callback).execute() initDeferred.await() // 等待初始化完成 } } companion object { val instance by lazy { AWSMobileClientManager() } } }
然后在Dagger模块中提供这个管理器,在Repository中注入它,并在使用DynamoDBMapper前先等待初始化:
// Dagger模块 @Module class AwsModule { @Singleton @Provides fun provideAWSMobileClientManager(): AWSMobileClientManager { return AWSMobileClientManager.instance } } // Repository类 class MyRepository @Inject constructor( private val awsManager: AWSMobileClientManager ) { // 延迟初始化Mapper,确保调用时AWSMobileClient已就绪 private val dynamoDbMapper: DynamoDBMapper by lazy { val credentials = awsManager.client.credentialsProvider val config = awsManager.client.configuration val ddbClient = AmazonDynamoDBClient(credentials).apply { setRegion(Region.getRegion(Regions.EU_WEST_2)) } DynamoDBMapper.builder() .awsConfiguration(config) .dynamoDBClient(ddbClient) .build() } suspend fun getSomeData(itemId: String): MyDataItem? { // 先确保AWSMobileClient初始化完成 awsManager.initialize(ApplicationProvider.getApplicationContext()) // 再使用Mapper return dynamoDbMapper.load(MyDataItem::class.java, itemId) } }
这种方式无需调整Dagger组件的初始化时机,而是把等待逻辑封装在Repository层,更灵活。
额外提示:考虑升级AWS SDK
你当前使用的AmazonDynamoDBClient是AWS SDK v1的类,官方已经推荐使用v2的DynamoDbClient(通过DynamoDbClient.builder()创建),v2的初始化方式更简洁,也更容易和协程等现代Android架构结合,建议后续考虑升级。
内容的提问来源于stack exchange,提问作者OliverDeLange
相关产品推荐
相关产品推荐

