协程不断崩溃而不显示错误

Posted

技术标签:

【中文标题】协程不断崩溃而不显示错误【英文标题】: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 是如何初始化的? 我尝试了您的解决方案,但它仍然崩溃。我已经用作用域的初始化更新了我的主题。 【参考方案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 块怎么办?也许堆栈跟踪中会出现一些东西。 我发布了我自己问题的答案。我要感谢您(非常感谢)分享您的文章,因为我找到了解决方案! 别忘了接受你自己的答案,因为它解释了问题的真正原因 明天才能做。谢谢你的提示!

以上是关于协程不断崩溃而不显示错误的主要内容,如果未能解决你的问题,请参考以下文章

当用户选择一个选项但随后将其更改为另一个选项时,React 崩溃而不显示错误

Flutter Bloc 不断重建小部件而不改变状态

Unity AndroidJavaObject 无法正常工作而不显示错误

无法从ViewModel向用户显示协程错误消息

Matlab从数组创建图像并保存而不显示

我的启动画面后我的程序不断崩溃。为啥?