首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在特定线程中使用回调,以便在主线程中等待它?

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

Stack Overflow用户
提问于 2021-06-04 05:54:33
回答 1查看 235关注 0票数 0

这里的第一个问题,我会尽我最大的努力。

我有一个数据类,它在创建时使用firestore检索数据对象。我已经用协程对setter编写了一些代码。我不确定我的解决方案,但它是有效的。然而,对于getter,我正在努力等待初始化。

在初始化过程中,我有一个回调函数来检索数据。回调总是从主线程调用的问题,如果我在另一个线程的协程中使用它,事件。我使用以下命令进行检查:

代码语言:javascript
运行
复制
Log.d("THREAD", "Execution thread1: "+Thread.currentThread().name)

对于设置器,我在useTask中使用协程来不阻塞主线程。和一个互斥锁来阻塞这个协程,直到初始化完成为止。不确定waitInitialisationSuspend,但它正在工作。

但对于getter,我只想阻塞主线程(即使它是糟糕的设计,这是第一个解决方案),直到初始化完成,并恢复getter以检索值。但我不能在初始化过程中阻塞主线程而不阻塞回调,因为在同一个线程中有。

我读了很多关于协程、作用域、runBlocking、线程等的文档,但是所有的东西都在我的脑海中混淆了。

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
runBlocking {
     initMutex.withLock {
         result = dbStory!!.value
     }
}

#2

代码语言:javascript
运行
复制
while (!isInitialized){
}
result = dbStory!!.value

#3因为可能init中的回调也在主线程中。我尝试使用IO调度程序在协程中启动此初始化,但没有成功。协程在另一个线程中运行良好,但回调仍然在主线程中调用。

代码语言:javascript
运行
复制
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
代码语言:javascript
运行
复制
scope.launch() {
            reference.get().addOnCompleteListener { task ->

在getter中,我必须使用主线程。解决方案可能是将回调执行放在另一个线程中,但我不知道怎么做。也许有更好的解决方案。

另一种解决方案是在主线程中等待回调,而不阻塞回调,但我没有解决方案。

有什么想法吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-06-05 15:18:58

我已经锁定了许多解决方案,结论是,不要这么做。

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

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

代码语言:javascript
运行
复制
Tasks.await(initTask)

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

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

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67829118

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档