2

I have a coroutine with an exception handler to call an API. I want to update UI if there is any exception but i got bellow error:

Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

So is there any way to update UI in exception handler?

Here is my code :

val exceptionHandler = CoroutineExceptionHandler { coroutineContext, exception ->

            binding.textview.text = exception.message

        }
        myJob = CoroutineScope(Dispatchers.IO).launch(exceptionHandler) {

            val result = webServices.getTest()

            withContext(Dispatchers.Main) {
                binding.textview.text = "$result"
            }
        }
2
  • as well as you did in the "normal" launch case you need to switch context to Dispatchers.Main Commented Dec 24, 2020 at 11:35
  • @NicolaGallazzi can you tell me how? Commented Dec 24, 2020 at 11:44

1 Answer 1

3

I think there is no way that ensures CoroutineExceptionHandler is called on Main thread. Because you can be on any thread at any time where the crash can happen.

Documentation

From CoroutineExceptionHandler

CoroutineExceptionHandler can be invoked from an arbitrary thread.

See also this Issue on GitHub

Workaround

You could launch a coroutine on main dispatcher, as Roman Elizarov mentioned, in your CoroutineExceptionHandler:

GlobalScope.launch(Dispatchers.Main) { ... /* put code here */ ...  }

or if you have a lifecycleScope (because GlobalScope is not recommended):

lifecycleScope.launch(Dispatchers.Main) { ... /* put code here */ ...  }
Sign up to request clarification or add additional context in comments.

4 Comments

Use lifecycleScope.launch {} by adding its relevant dependencies instead, GlobalScope.launch {} is not recommended.
@DarShan you are right, I updated my answer.
What if I don't have access to any lifecycleScope? I'm developing an SDK and the use of Coroutines needs to be an implementation detail; the SDK callers shouldn't need to know about it. My CoroutineExceptionHandler calls back to the SDK user's code. I want to switch back to Dispatchers.Main before calling back. Should I use GlobalScope.launch for this exceptional case?
Another case where I don't have access to lifecycleScope is in Android instrumented tests. How should we launch coroutines from Espresso tests?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.