Android Kotlin协程在严格模式下崩溃 [英] Android Kotlin coroutine crashing on strict mode
问题描述
我在下面为我的问题创建了一个非常简化的版本.
严格模式是通过以下策略设置的:
I have created a very simplified version of my issue below.
The strict mode is set up with the following policies:
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork() // or .detectAll() for all detectable problems
.penaltyLog()
.penaltyDeath()
.build()
)
视图模型只有一个函数,该函数在调用时会使应用程序崩溃.该函数不执行任何操作(它具有一个空的正文)
The view model has only one function which crashes the application when invoked. The function does nothing (it has an empty body)
class MyViewModel : ViewModel() {
fun foo() {
viewModelScope.launch(Dispatchers.IO){ }
}
}
该活动将调用onCreate
中的viewModel.foo()
,这将导致具有以下跟踪信息的应用程序崩溃.
The activity invokes viewModel.foo()
in onCreate
which crashes the application with the following trace.
--------- beginning of crash
2019-04-08 22:07:49.579 1471-1471/com.example.myapplication E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.myapplication, PID: 1471
java.lang.RuntimeException: StrictMode ThreadPolicy violation
at android.os.StrictMode$AndroidBlockGuardPolicy.onThreadPolicyViolation(StrictMode.java:1705)
at android.os.StrictMode$AndroidBlockGuardPolicy.lambda$handleViolationWithTimingAttempt$0(StrictMode.java:1619)
at android.os.-$$Lambda$StrictMode$AndroidBlockGuardPolicy$9nBulCQKaMajrWr41SB7f7YRT1I.run(Unknown Source:6)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: android.os.strictmode.DiskReadViolation
at android.os.StrictMode$AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1504)
at java.io.UnixFileSystem.getBooleanAttributes(UnixFileSystem.java:241)
at java.io.File.isDirectory(File.java:845)
at dalvik.system.DexPathList$Element.maybeInit(DexPathList.java:696)
at dalvik.system.DexPathList$Element.findResource(DexPathList.java:729)
at dalvik.system.DexPathList.findResources(DexPathList.java:526)
at dalvik.system.BaseDexClassLoader.findResources(BaseDexClassLoader.java:174)
at java.lang.ClassLoader.getResources(ClassLoader.java:839)
at java.util.ServiceLoader$LazyIterator.hasNextService(ServiceLoader.java:349)
at java.util.ServiceLoader$LazyIterator.hasNext(ServiceLoader.java:402)
at java.util.ServiceLoader$1.hasNext(ServiceLoader.java:488)
at kotlin.collections.CollectionsKt___CollectionsKt.toCollection(_Collections.kt:1145)
at kotlin.collections.CollectionsKt___CollectionsKt.toMutableList(_Collections.kt:1178)
at kotlin.collections.CollectionsKt___CollectionsKt.toList(_Collections.kt:1169)
at kotlinx.coroutines.internal.MainDispatcherLoader.loadMainDispatcher(MainDispatchers.kt:15)
at kotlinx.coroutines.internal.MainDispatcherLoader.<clinit>(MainDispatchers.kt:10)
at kotlinx.coroutines.Dispatchers.getMain(Dispatchers.kt:55)
at androidx.lifecycle.ViewModelKt.getViewModelScope(ViewModel.kt:41)
at com.example.myapplication.MyViewModel.foo(MainActivity.kt:35)
at com.example.myapplication.MainActivity.onCreate(MainActivity.kt:28)
at android.app.Activity.performCreate(Activity.java:7136)
at android.app.Activity.performCreate(Activity.java:7127)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
根据堆栈跟踪,有磁盘读取冲突,但是该代码中的任何内容都不应访问磁盘.
感兴趣的行是:
According to the stack trace there is a disk read violation but nothing in that code should be accessing disk.
The lines of interest are:
at com.example.myapplication.MyViewModel.foo(MainActivity.kt:35)
at com.example.myapplication.MainActivity.onCreate(MainActivity.kt:28)
第35行:viewModelScope.launch(Dispatchers.IO){ }
第28行:viewModel.foo()
如果我删除penaltyLog()
,则该应用程序不会崩溃.
Further more if I remove penaltyLog()
then the application does not crash.
所以我的问题是
如何使用上面的严格模式配置防止崩溃?
协程本身或严格模式本身是否有问题?
更新: 这似乎是协程的一个已知问题.仍未解决-在此处
Update: This seems to be a known issue with coroutines. Still unresolved - see the conversation here
推荐答案
解决方案是使用您自己初始化的调度程序,而无需在主线程上执行I/O.
The solution is to use your own dispatcher that you initialize without doing I/O on the main thread.
实现起来有点棘手,因为要避免由于Handler
上默认启用了vsync(可能会延迟多达16ms的代码,根本不需要vsync)而导致应用速度降低,您必须使用API 28岁以上的构造函数,并将反射用于较旧的Android版本.之后,您可以将asCoroutineDispatcher()
扩展功能用于Handler
,并使用生成的调度程序.
It's a bit tricky to implement because to avoid slowing down your app because of vsync enabled by default on Handler
(could delay by up to 16ms code that doesn't need vsync at all), you have to use an API 28+ constructor, and use reflection for older versions of Android. After doing that, you can use the asCoroutineDispatcher()
extension function for Handler
, and use the resulting dispatcher.
为了让我和其他人更容易使用,我制作了一个(小型)库,该库提供了Dispatchers.MainAndroid
扩展名,该扩展名是延迟初始化的,没有任何I/O,可以代替Dispatchers.Main
使用.它还将Lifecycle
与协同程序范围集成在一起.
To make it simpler for me, and others, I made a (small) library that provides a Dispatchers.MainAndroid
extension that is lazily initialized without any I/O and can be used in place of Dispatchers.Main
. It also integrated Lifecycle
with coroutine scopes.
在这里,您可以查看如何获取依赖关系(可在jcenter上获得)以及如何实现依赖关系:
Here's the link where you can see how to get the dependency (available on jcenter) and how it is implemented: https://github.com/LouisCAD/Splitties/tree/master/modules/lifecycle-coroutines
这篇关于Android Kotlin协程在严格模式下崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!