【问题标题】:Coroutine keeps crashing without showing error协程不断崩溃而不显示错误
【发布时间】:2021-01-29 02:48:40
【问题描述】:

我正在开发 MVP。在我的 Presenter 中,由于挂起功能,我调用了我的存储库。在这个挂起函数中,我启动了一个协程——而不是在主线程上。 当这个协程完成后,我想执行一些代码:我正在使用 withContext() 来执行此操作。

在我的存储库中,我正在启动一个协程(也许我错了)以使用 DAO 将我的数据插入到我的 Room 数据库中。

当我调试我的应用程序时,它会进入我的 Presenter,但在进入我的存储库之前会崩溃。

演讲者

    override suspend fun insertUserResponse(activity: Activity, data: UserResponse) {
        scope.launch(Dispatchers.IO) {
            try {
                userResponseRepository.insertUserResponse(data)

                withContext(Dispatchers.Main) {
                    redirectToClientMainPage(activity)
                }
            } catch (error: Exception) {
                parentJob.cancel()
                Log.e("ERROR PRESENTER", "${error.message}")
            }
        }
    }

存储库

    override suspend fun insertUserResponse(userResponse: UserResponse) {
        GlobalScope.launch(Dispatchers.IO) {
            try {
                val existingUser: UserResponse? =
                    userResponseDAO.searchUserByID(userResponse.profilePOJO.uniqueID)

                existingUser?.let {
                    userResponseDAO.updateUser(userResponse)
                } ?: userResponseDAO.insertUser(userResponse)
            } catch (error: Exception) {
                Log.e("ERROR REPOSITORY", "${error.message}")
            }
        }

    }

我的 logcat 中没有显示错误。

编辑:

作用域初始化

    private var parentJob: Job = Job()

    override val coroutineContext: CoroutineContext
        get() = uiContext + parentJob

    private val scope = CoroutineScope(coroutineContext)

val uiContext: CoroutineContext = Dispatchers.Main(在我的类构造函数中初始化)

堆栈跟踪

【问题讨论】:

  • 在存储库中将 GlobalScope.launch 更改为 withContext 。以及scope 是如何初始化的?
  • 我尝试了您的解决方案,但它仍然崩溃。我已经用作用域的初始化更新了我的主题。

标签: android kotlin android-room androidx kotlin-coroutines


【解决方案1】:

我终于找到了答案!

感谢@sergiy,我阅读了这篇文章的第二部分https://medium.com/androiddevelopers/coroutines-on-android-part-ii-getting-started-3bff117176dd,其中提到除了 Throwable 和 CancellationException 之外,您无法捕获错误。

因此,我没有捕获 Exception,而是将其换成了 Throwable。最后,我的 logcat 中显示了一个错误。

我正在使用 Koin 注入我的存储库和所有内容。我的 Koin 应用程序中缺少我的 androidContext()。 就是这样。

【讨论】:

    【解决方案2】:

    没有堆栈跟踪,很难为您提供帮助。

    Here 是一篇文章,可能会有所帮助。在您的情况下,将文章中提到的ViewModel 替换为Presenter,您可以获得一些使用协程的一般建议:

    作为一般模式,在 ViewModel 中启动协程(阅读:Presenter)

    我认为不需要在 Repository 中再启动一个协程。

    至于切换Room的协程上下文:

    Room 使用自己的调度程序在后台线程上运行查询。您的代码不应使用 withContext(Dispatchers.IO) 来调用暂停房间查询。它会使代码复杂化并使您的查询运行速度变慢。

    我在官方文档中找不到相同的建议,但在one of the Google code labs 中提到了。

    Room 和 Retrofit 都使挂起功能成为主要安全的。 从 Dispatchers.Main 调用这些挂起函数是安全的,即使它们从网络获取并写入数据库。

    所以你可以在 Repository 中省略 launch(以及 withContext),因为 Room 保证所有带有 suspend 的方法都是主安全的。这意味着它们甚至可以从主线程调用。您也不能在Presenter 中明确定义Dispatchers.IO

    还有一件事。如果 Presenter 的方法 insertUserResponse 是挂起,那么你从另一个启动的协程调用它,不是吗?在那种情况下,为什么要在这个方法中再启动一个协程呢?或者这个方法不应该是suspend

    【讨论】:

    • 我用我的堆栈跟踪屏幕编辑了我的初始帖子。我没有看到任何有用的东西,但也许你会。另外,关于你的最后一点,我使用了暂停,因为我首先尝试使用 async/await 启动我的协程,以便在执行我的下一行代码(我的重定向)之前等待协程完成。我稍后编辑了我的函数,忘记删除suspend关键字。
    • 如果你注释掉你的 try-catch 块怎么办?也许堆栈跟踪中会出现一些东西。
    • 我发布了我自己问题的答案。我要感谢您(非常感谢)分享您的文章,因为我找到了解决方案!
    • 别忘了接受你自己的答案,因为它解释了问题的真正原因
    • 明天才能做。谢谢你的提示!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-25
    • 2010-10-22
    相关资源
    最近更新 更多