Android Kotlin协程在严格模式下崩溃 [英] Android Kotlin coroutine crashing on strict mode

查看:184
本文介绍了Android Kotlin协程在严格模式下崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在下面为我的问题创建了一个非常简化的版本.
严格模式是通过以下策略设置的:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆