Reputation: 9380
I am trying to do simple request to backend with coroutines
uiScope.launch {
try {
result = URL("https://httpbin.org/get").readText()
text.text = result
} catch (error: Error) {
text.text = error.message
} finally {
log(this@MainActivity,result)
}
}
but this exeption is thrown:
android.view.ViewRootImpl$CalledFromWrongThreadException
: Only the original thread that created a view hierarchy can touch its views.
How to solve it?
Upvotes: 1
Views: 1104
Reputation: 9380
I found solution. I can not access UI component from another thread, at the same time I can not make internet request on the main thread. So I should chouse one of them. Solution was to use ViewModel components and update it's LiveDate value which subsequently will chane the UI
var viewModel = ViewModelProviders.of(this).get(MyViewModel::class.java)
viewModel.selected.observe(this, Observer{ users ->
text.text = users
})
uiScope.launch {
try {
result = URL("http://jsonplaceholder.typicode.com/posts").readText()
viewModel.selected.postValue(result)
} catch (error: Error) {
viewModel.selected.postValue(error.toString())
}
}
log(this@MainActivity,result)
Upvotes: 2
Reputation: 200148
Your uiScope
isn't set up correctly, apparently its dispatcher is not Dispatchers.Main
. So the first thing to fix is your implementation of the coroutineContext
property, which should be
override val coroutineContext = Dispatchers.Main + SupervisorJob()
Once you fix that, your code will be making a blocking call on the UI thread. To make the blocking call on a background thread, but still keep the rest of the coroutine on the UI thread, write
uiScope.launch {
try {
text.text = withContext(Dispatchers.IO) {
URL("https://httpbin.org/get").readText()
}
} catch (e: Exception) {
text.text = e.message
} finally {
log(this@MainActivity, result)
}
}
Upvotes: 0