I am using Kotlin corountines in my Android Project. I am trying to download some data and display in a textview.
Following is my code
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
tv.setOnClickListener {
downloadData()
}
}
private fun downloadData() {
runBlocking {
pb_activity_main.visibility = View.VISIBLE
var data = ""
async {
data = downloadDataBlocking()
}.await()
tv.text = data
pb_activity_main.visibility = View.GONE
}
}
private fun downloadDataBlocking(): String {
val client = OkHttpClient()
val request = Request.Builder().url("https://jsonplaceholder.typicode.com/posts").build()
val response = client.newCall(request).execute()
return response.body()?.string() ?: ""
}
}
But the data is not downloaded. I am not able to figure out why.
I have included the internet permission in Manifest and the url is also working.
Try this:
class MainActivity : AppCompatActivity(), CoroutineScope {
private val job = Job()
override val coroutineContext = Dispatchers.Main + job
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
tv.setOnClickListener {
downloadData()
}
}
private fun downloadData() {
launch {
pb_activity_main.visibility = View.VISIBLE
tv.text = withContext(Dispatchers.IO) { downloadDataBlocking() }
pb_activity_main.visibility = View.GONE
}
}
private fun downloadDataBlocking(): String {
val client = OkHttpClient()
val request = Request.Builder().url("https://jsonplaceholder.typicode.com/posts").build()
val response = client.newCall(request).execute()
return response.body()?.string() ?: ""
}
}
First: you should never use runBLocking
out of unit-testing or other special domain.
This function should not be used from coroutine. It is designed to bridge regular blocking code to libraries that are written in suspending style, to be used in main functions and in tests.
Second:
Coroutines are always related to some local scope in your application, which is an entity with a limited life-time, like a UI element.
That's why Activity
implements CoroutineScope
. Honestly, a better place for it is ViewModel
or Presenter
, but I don't see any in the code...
Third, it is quite pointless to useasync
and await
right after it's definition. Just use withContext
then.