java.lang.RuntimeException: Methods marked with @UiThread must be executed on the main thread. Current thread: DefaultDispatcher-worker-2

有些话、适合烂在心里 提交于 2021-01-29 05:50:33

问题


I'm quite new about flutter and kotlin. I'm doing flutter version up(from 1.0.0 to 1.7.8+hotfix4) recently. After I upgrade kotlin version to 1.3.10, my flutter app came into crash when I try to start it.

And the error shows like this :

[ +521 ms] E/AndroidRuntime( 2726): FATAL EXCEPTION: DefaultDispatcher-worker-2
[+1 ms] E/AndroidRuntime( 2726): Process: XXXXXXXXXXXX, PID: 2726 
[        ] E/AndroidRuntime( 2726): java.lang.RuntimeException: Methods marked with @UiThread must be executed on the main thread. Current thread: DefaultDispatcher-worker-2
[        ] E/AndroidRuntime( 2726):     at io.flutter.embedding.engine.FlutterJNI.ensureRunningOnMainThread(FlutterJNI.java:794) 
[   +1 ms] E/AndroidRuntime( 2726):     at io.flutter.embedding.engine.FlutterJNI.invokePlatformMessageResponseCallback(FlutterJNI.java:727) 
[   +1 ms] E/AndroidRuntime( 2726):     at io.flutter.embedding.engine.dart.DartMessenger$Reply.reply(DartMessenger.java:140) 
[   +1 ms] E/AndroidRuntime( 2726):     at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler$1.success(MethodChannel.java:225) 
[   +1 ms] E/AndroidRuntime( 2726):     at XXXXXXXXXXXX.MainActivity$onActivityResult$1.invokeSuspend(MainActivity.kt:91) 
[        ] E/AndroidRuntime( 2726):     at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) 
[        ] E/AndroidRuntime( 2726):     at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:241) 
[        ] E/AndroidRuntime( 2726):     at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594) 
[        ] E/AndroidRuntime( 2726):     at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60) 
[        ] E/AndroidRuntime( 2726):     at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:740) 
[  +14 ms] D/AutoManageHelper( 2726): onStart true {99992=com.google.android.gms.internal.zzbau$zza@72d039a} 
[ +983 ms] I/CrashlyticsCore( 2726): Crashlytics report upload complete: 5D72013C01D2-0001-0AA6-12B9D92A3973

This is the setting in build.gradle:

ext.kotlin_coroutines_version = "1.3.0"
ext.okhttp_version = "3.12.0"

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$kotlin_coroutines_version"

Here is the code in MainActivity:

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.launch

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    when (requestCode) {
      LOGIN_CODE ->
        if (resultCode == RESULT_OK) {
          if (LoginManager.getInstance().loginService.isLoggedIn) {
            GlobalScope.launch {
              async {
                var ls = LoginManager.getInstance().loginService
                var response = ls.authRequest<AuthResponse<TokenResult>>(AUTH_PROVIDER_NAME)
                return@async response.getToken()
              }.await().let {
                methodResult?.success(it)
              }
            }
          }
        } else {
          methodResult?.success("")
        }

      LOGOUT_CODE ->
        if (resultCode == RESULT_OK) {
          methodResult?.success(true)
        }

      REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA -> {
        if (resultCode != RESULT_OK) {
          methodResult?.success("")
        }
      }

      else -> {
        methodResult?.success(false)
      }
    }
  }

回答1:


First of all you should avoid using global scope, it is equivalent to creating a thread in java, you can read more here about this.

Second thing is that you should know that you can modify UI only on the Main thread. Most probably methodResult?.success(it) does some UI updates, so if you want a fast fix :

GlobalScope.launch {
              async {
                var ls = LoginManager.getInstance().loginService
                var response = ls.authRequest<AuthResponse<TokenResult>>(AUTH_PROVIDER_NAME)
                return@async response.getToken()
              }.await().let {
                withContext(Dispatchers.Main) {
                  methodResult?.success(it)
                }
              }
            }

When you call GlobalScope.launch it implies that you launch the coroutine as Dispatchers.Default witch means it will create a worker thread that is usually used for intensive computation, if you use it for network requests a better solution would be to launch it with dispatchers IO:

// instead of GlobalScope.launch 
CoroutineScope(Dispatchers.IO).launch {
  // your code goes here
}


来源:https://stackoverflow.com/questions/57817304/java-lang-runtimeexception-methods-marked-with-uithread-must-be-executed-on-th

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!