如何在同步代码块中调用一个挂起函数来实例化一个已连接的PowerSyncDatabase?
我正在尝试创建一个单例,用来返回一个 PowerSyncDatabase 的实例。
class OnlineSyncDatabase {
companion object {
// @Volatile
private val instance: PowerSyncDatabase? = null
val dotenv = dotenv()
suspend fun getDatabase(applicationContext: Context): PowerSyncDatabase {
return instance?: synchronized(this) {
val driverFactory = DatabaseDriverFactory(applicationContext)
val supabaseClient = createSupabaseClient(
supabaseUrl = dotenv["SUPABASE_URL"],
supabaseKey = dotenv["SUPABASE_KEY"]
) {
install(Postgrest)
install(Auth)
}
val powerSyncDatabase = PowerSyncDatabase(
factory = driverFactory,
schema = AppSchema,
dbFilename = "powersync.db"
)
powerSyncDatabase.connect(SupabaseConnector(
supabaseClient,
dotenv["POWERSYNC_URL"]
))
powerSyncDatabase
}
}
}
}
然而,编译器对挂起函数 connect(SupabaseConnector...) 抛出一个错误:
“connect” 的挂起点位于临界区内部。
不过我还不知道还能放在哪里。我该如何实例化一个已连接的 PowerSyncDatabase 实例?
解决方案
我不确定你为什么不像在前一个问题中那样使用Hilt,但如果你坚持,你当然也可以手动获取一个实例。
在这种情况下,只需将 connect() 调用移动到synchronized块之外:
private var instance: PowerSyncDatabase? = null
suspend fun getDatabase(applicationContext: Context): PowerSyncDatabase =
synchronized(this) {
instance?.let { return@getDatabase it }
val driverFactory = DatabaseDriverFactory(applicationContext)
PowerSyncDatabase(
factory = driverFactory,
schema = AppSchema,
dbFilename = "powersync.db",
).also { instance = it }
}.apply {
val supabaseClient = createSupabaseClient(
supabaseUrl = dotenv["SUPABASE_URL"],
supabaseKey = dotenv["SUPABASE_KEY"],
) {
install(Postgrest)
install(Auth)
}
connect(
SupabaseConnector(
supabaseClient = supabaseClient,
powerSyncEndpoint = dotenv["POWERSYNC_URL"],
)
)
}
现在连接是在 synchronized 块完成之后才开始,因此你不再需要在 synchronized 块内部挂起——错误信息正是提醒你这一点。
请注意,我还将检查实例是否已存在的判断移动到了 synchronized 块内。否则如果有两个线程同时调用这个函数,它们都会检测到 instance 为null,然后同时进入 synchronized 块。尽管因为该块是同步的,这两次进入会一个接一个地发生,但它们仍然会执行相同的代码,创建两个独立的PowerSyncDatabase实例。使用修正后的代码,一旦先前的调用已经初始化(并随后也已连接)的实例存在,synchronized 块将立即退出整个 getDatabase() 函数,从而维持所需的单例语义。
嗯,如果你仍在使用Hilt,做起来就像简单地应用 @Singleton 注解一样容易。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。