协程不断崩溃而不显示错误
Coroutine keeps crashing without showing error
我正在开发 MVP。在我的 Presenter 中,由于挂起功能,我调用了我的 Repository。在这个挂起函数中,我启动了一个协程——而不是在主线程上。
当这个协程完成时,我想执行一些代码:我正在使用 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(在我的 class 构造函数中初始化)
堆栈跟踪
没有堆栈跟踪,很难帮到你。
Here 是一篇文章,可能会有帮助。在您的情况下,将文章中提到的 ViewModel
替换为 Presenter
,您可以获得使用协程的几个一般性建议:
As a general pattern, start coroutines in the ViewModel (Read: Presenter)
我认为没有必要在您的 Repository 案例中再启动一个协程。
关于为 Room 切换协程的上下文:
Room uses its own dispatcher to run queries on a background thread. Your code should not use withContext(Dispatchers.IO) to call suspending room queries. It will complicate the code and make your queries run slower.
我在官方文档中找不到相同的推荐,但在 one of the Google code labs 中提到了。
Both Room and Retrofit make suspending functions main-safe.
It's safe to call these suspend funs from Dispatchers.Main, even though they fetch from the network and write to the database.
因此您可以在 Repository 中省略 launch
(以及 withContext
),因为 Room 保证所有带有 suspend
的方法都是 main-safe。这意味着它们甚至可以从主线程调用。您也不能在 Presenter
.
中明确定义 Dispatchers.IO
还有一件事。如果 Presenter 的方法 insertUserResponse
被挂起,那么你从另一个启动的协程调用它,不是吗?既然如此,为什么还要在这个方法中启动一个协程?或者这个方法不应该是 suspend
?
终于找到答案了!
感谢@sergiy,我阅读了这篇文章的第二部分 https://medium.com/androiddevelopers/coroutines-on-android-part-ii-getting-started-3bff117176dd,它提到除了 Throwable 和 CancellationException 之外你无法捕获错误。
所以我没有捕获 Exception,而是将它换成了 Throwable。最后,我的 logcat.
中显示了一个错误
我正在使用 Koin 注入我的存储库和所有内容。我在我的 Koin 应用程序中缺少我的 androidContext() 。
就是这样。
我正在开发 MVP。在我的 Presenter 中,由于挂起功能,我调用了我的 Repository。在这个挂起函数中,我启动了一个协程——而不是在主线程上。 当这个协程完成时,我想执行一些代码:我正在使用 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(在我的 class 构造函数中初始化)
堆栈跟踪
没有堆栈跟踪,很难帮到你。
Here 是一篇文章,可能会有帮助。在您的情况下,将文章中提到的 ViewModel
替换为 Presenter
,您可以获得使用协程的几个一般性建议:
As a general pattern, start coroutines in the ViewModel (Read: Presenter)
我认为没有必要在您的 Repository 案例中再启动一个协程。
关于为 Room 切换协程的上下文:
Room uses its own dispatcher to run queries on a background thread. Your code should not use withContext(Dispatchers.IO) to call suspending room queries. It will complicate the code and make your queries run slower.
我在官方文档中找不到相同的推荐,但在 one of the Google code labs 中提到了。
Both Room and Retrofit make suspending functions main-safe. It's safe to call these suspend funs from Dispatchers.Main, even though they fetch from the network and write to the database.
因此您可以在 Repository 中省略 launch
(以及 withContext
),因为 Room 保证所有带有 suspend
的方法都是 main-safe。这意味着它们甚至可以从主线程调用。您也不能在 Presenter
.
Dispatchers.IO
还有一件事。如果 Presenter 的方法 insertUserResponse
被挂起,那么你从另一个启动的协程调用它,不是吗?既然如此,为什么还要在这个方法中启动一个协程?或者这个方法不应该是 suspend
?
终于找到答案了!
感谢@sergiy,我阅读了这篇文章的第二部分 https://medium.com/androiddevelopers/coroutines-on-android-part-ii-getting-started-3bff117176dd,它提到除了 Throwable 和 CancellationException 之外你无法捕获错误。
所以我没有捕获 Exception,而是将它换成了 Throwable。最后,我的 logcat.
中显示了一个错误我正在使用 Koin 注入我的存储库和所有内容。我在我的 Koin 应用程序中缺少我的 androidContext() 。 就是这样。