这里的第一个问题,我会尽我最大的努力。
我有一个数据类,它在创建时使用firestore检索数据对象。我已经用协程对setter编写了一些代码。我不确定我的解决方案,但它是有效的。然而,对于getter,我正在努力等待初始化。
在初始化过程中,我有一个回调函数来检索数据。回调总是从主线程调用的问题,如果我在另一个线程的协程中使用它,事件。我使用以下命令进行检查:
Log.d("THREAD", "Execution thread1: "+Thread.currentThread().name)对于设置器,我在useTask中使用协程来不阻塞主线程。和一个互斥锁来阻塞这个协程,直到初始化完成为止。不确定waitInitialisationSuspend,但它正在工作。
但对于getter,我只想阻塞主线程(即使它是糟糕的设计,这是第一个解决方案),直到初始化完成,并恢复getter以检索值。但我不能在初始化过程中阻塞主线程而不阻塞回调,因为在同一个线程中有。
我读了很多关于协程、作用域、runBlocking、线程等的文档,但是所有的东西都在我的脑海中混淆了。
class Story(val id: String) : BaseObservable() {
private val storyRef = StoryHelper.getStoryRef(id)!!
private var isInitialized = false
private val initMutex = Mutex(true)
@get:Bindable
var dbStory: DbStory? = null
init {
storyRef.get().addOnCompleteListener { task ->
if (task.isSuccessful && task.result != null) {
dbStory = snapshot.toObject(DbStory::class.java)!!
if (!isInitialized) {
initMutex.unlock()
isInitialized = true
}
notifyPropertyChanged(BR.dbStory)
}
}
}
fun interface StoryListener {
fun onEvent()
}
private fun useTask(function: (task: Task) -> Unit): Task {
val task = Task()
GlobalScope.launch {
waitInitialisationSuspend()
function(task)
}
return task
}
private suspend fun waitInitialisationSuspend()
{
initMutex.withLock {
// no op wait for unlock mutex
}
}
fun typicalSetFunction(value: String) : Task {
return useTask { task ->
storyRef.update("fieldName", value).addOnSuccessListener {
task.doEvent()
}
}
}
fun typicalGetFunction(): String
{
var result = ""
// want something to wait the callback in the init.
return result
}
}RunBlocking似乎阻塞了主线程,所以如果回调仍然使用主线程,我就不能使用它。如果我在主线程中使用while循环,也会出现同样的问题。
#1
runBlocking {
initMutex.withLock {
result = dbStory!!.value
}
}#2
while (!isInitialized){
}
result = dbStory!!.value#3因为可能init中的回调也在主线程中。我尝试使用IO调度程序在协程中启动此初始化,但没有成功。协程在另一个线程中运行良好,但回调仍然在主线程中调用。
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())scope.launch() {
reference.get().addOnCompleteListener { task ->在getter中,我必须使用主线程。解决方案可能是将回调执行放在另一个线程中,但我不知道怎么做。也许有更好的解决方案。
另一种解决方案是在主线程中等待回调,而不阻塞回调,但我没有解决方案。
有什么想法吗?
发布于 2021-06-05 15:18:58
我已经锁定了许多解决方案,结论是,不要这么做。
这个设计比我想象的还要糟糕。Android不希望你阻塞主线程,即使是很短的时间。阻塞主线程就是阻塞所有的UI和同步机制,这真是一个糟糕的解决方案。
我认为,即使使用另一个线程进行回调(您可以使用Executor),在这里也不是一个好主意。在回调中等待任务结束的好方法是检索任务并使用:
Tasks.await(initTask)但在主线程中是不允许的。Android可以防止你在这里做糟糕的设计。
我们应该采用异步方式来管理firebase数据库,这是最好的方式。我仍然可以在数据上使用我的缓存。在这里,我正在等待显示一个对话框,其中包含我在firebase中检索到的文本。因此,我可以在检索文本数据时异步显示对话框。如果缓存可用,它将使用它。
还请记住,firebase似乎有一些使用缓存的API。
https://stackoverflow.com/questions/67829118
复制相似问题