I was using Kotlin to make a basic Currency converter app with an API. To download information, I have created a new class called DownloadTaskClass that extends the deprecated AsyncTask class (I haven't learned the other classes of the java.util.concurrent package).
The DownloadTaskClass contains a method to return a MutableMap to the MainActivity. However, I cannot understand why this method isn't returning the MutableMap object. Here are the classes.
DownloadTaskClass.kt
package com.example.kotlincurrency
import android.os.AsyncTask
import org.json.JSONObject
import java.io.InputStream
import java.io.InputStreamReader
import java.lang.Exception
import java.net.HttpURLConnection
import java.net.URL
class DownloadTaskClass: AsyncTask<String, Void, String>() {
private var data: Int = 0
private var result: String = ""
private var mutableMap: MutableMap<String, Any> = mutableMapOf()
private lateinit var url: URL
private lateinit var inputStream: InputStream
private lateinit var inputStreamReader: InputStreamReader
private lateinit var httpURLConnection: HttpURLConnection
override fun doInBackground(vararg urls: String): String? {
url = URL(urls[0])
httpURLConnection = url.openConnection() as HttpURLConnection
inputStream = httpURLConnection.inputStream
inputStreamReader = InputStreamReader(inputStream)
data = inputStreamReader.read()
while (data != -1){
val current: Char = data.toChar()
result += current
data = inputStreamReader.read()
}
return result
}
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
try {
val jsonObject = JSONObject(result)
mutableMap["date"] = jsonObject.getString("date")
val rates: String = jsonObject.getString("rates")
val currencyJSONObject = JSONObject(rates)
mutableMap["USD"] = currencyJSONObject.getString("USD")
mutableMap["GBP"] = currencyJSONObject.getString("GBP")
mutableMap["EUR"] = currencyJSONObject.getString("EUR")
mutableMap["CHF"] = currencyJSONObject.getString("CHF")
mutableMap["SEK"] = currencyJSONObject.getString("SEK")
mutableMap["CAD"] = currencyJSONObject.getString("CAD")
}
catch (e: Exception){
e.printStackTrace()
}
}
fun returnMapMethod(): MutableMap<String, Any>{
return mutableMap
}
}
MainActivity.kt
package com.example.kotlincurrency
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.appcompat.app.ActionBar
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setActionBar()
downloadInitInfo()
}
private fun setActionBar() {
supportActionBar!!.displayOptions = ActionBar.DISPLAY_SHOW_CUSTOM
supportActionBar!!.setDisplayShowCustomEnabled(true)
supportActionBar!!.setCustomView(R.layout.layout_action_bar)
}
private fun downloadInitInfo(){
val downloadTaskClass = DownloadTaskClass()
downloadTaskClass.execute("https://api.exchangeratesapi.io/latest?base=INR")
println(downloadTaskClass.returnMapMethod())
}
}
You make an asynchronous request in doInBackground()
method, it may take some time before onPostExecute()
is called and mutableMap
is filled with data. When you call returnMapMethod()
method mutableMap
object hasn't been filled with data yet. You need to use some listener to be notified when the data is loaded.
Here is an example of using LiveData
to observe data:
class DownloadTaskClass: AsyncTask<String, Void, String>() {
private var data: MutableLiveData<MutableMap<String, Any>> = MutableLiveData()
// ...
override fun onPostExecute(result: String?) {
// ...
data.value = mutableMap
}
fun returnMapMethod(): LiveData<out Map<String, Any>> {
return data
}
}
In your Activity:
private fun downloadInitInfo(){
val downloadTaskClass = DownloadTaskClass()
downloadTaskClass.execute("https://api.exchangeratesapi.io/latest?base=INR")
downloadTaskClass.returnMapMethod().observe(this, Observer {
println(it) // "it" contains the `mutableMap` data
})
}