如何在特定线程中使用回调以在主线程中等待它?

耶利米·帕拉斯

第一个问题在这里,我会尽力而为。

我有一个 Data 类,它在创建时使用 firestore 检索数据对象。我已经用协程为 setter 做了一些代码。我不确定我的解决方案,但它正在工作。但是,对于吸气剂,我正在努力等待初始化。

在初始化中,我有一个回调来检索数据。回调总是从主线程调用的问题,如果我在另一个线程的协程中使用它,则事件发生。我用以下方法检查:

Log.d("THREAD", "Execution thread1: "+Thread.currentThread().name)

对于 setter,我在 useTask 中使用协程来不阻塞主线程。还有一个互斥锁来阻塞这个协程,直到 init 中的初始化完成。不确定 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 中,我必须使用主线程。解决方案可能是将回调执行放在另一个线程中,但我不知道如何执行此操作。也许有更好的解决方案。

另一种解决方案是能够在不阻塞回调的情况下等待主线程中的回调,但我对此没有解决方案。

有任何想法吗 ?

耶利米·帕拉斯

我已经寻找了很多解决方案,结论是,不要这样做。

这个设计比我想象的要糟糕。Android 不希望您阻塞主线程,即使是很短的时间。阻塞主线程就是阻塞所有 UI 和同步机制,这真的是一个糟糕的解决方案。

我认为,即使使用另一个线程进行回调(您可以使用 Executor 执行)在这里也是一个坏主意。在回调中等待任务结束的好方法是检索任务并使用:

''' Tasks.await(initTask) '''

但是在主线程中是不允许的。Android 阻止你在这里做糟糕的设计。

我们应该处理管理firebase 数据库的异步方式,这是最好的方式。我仍然可以在数据上使用我的缓存。在这里,我正在等待显示一个对话框,其中包含我在 firebase 中检索到的文本。因此,我可以在检索文本数据时异步显示对话框。如果缓存可用,它将使用它。

还要记住,firebase 似乎有一些 API 来使用缓存。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章