Reputation: 736
I have a Currency Converter Android app. I 'm using retrofit for getting rates from API but as far as I'm concerned my app can't get data from api and it returns that exception
Unable to invoke no-args constructor for class package name
.ConversionRates
. Registering an InstanceCreator with Gson for this type may fix this problem.
ConversionRates data class:
data class ConversionRates(
val AED: Double,
val AFN: Double,
val ALL: Double,
val AMD: Double,
val ANG: Double,
val AOA: Double,
val ARS: Double,
val AUD: Double,
val AWG: Double,
val AZN: Double,
val BAM: Double,
val BBD: Double,
val BDT: Double,
val BGN: Double,
val BHD: Double,
val BIF: Double,
val BMD: Double,
val BND: Double,
val BOB: Double,
val BRL: Double,
val BSD: Double,
val BTN: Double,
val BWP: Double,)
viewModel:
@HiltViewModelclass MainViewModel @Inject constructor(
private val repository: MainRepository,
private val dispatchers: DispatcherProvider) : ViewModel(){
sealed class CurrencyEvent {
class Success(val resultText: String): CurrencyEvent()
class Failure(val errorText: String): CurrencyEvent()
object Loading: CurrencyEvent()
object Empty: CurrencyEvent() }
private val _conversion= MutableStateFlow<CurrencyEvent>(CurrencyEvent.Empty)
val conversion: StateFlow<CurrencyEvent> = _conversion
fun convert(amountStr: String,
fromCurrency: String,
toCurrency: String ){
val fromAmount= amountStr.toFloatOrNull()
if( fromAmount== null){
_conversion.value=CurrencyEvent.Failure("Not a valid amount")
return
}
viewModelScope.launch (dispatchers.io){
_conversion.value= CurrencyEvent.Loading
when( val ratesResponse= repository.getRates(fromCurrency)) {
is Resource.Error -> _conversion.value= CurrencyEvent.Failure(ratesResponse.message!!)
is Resource.Success -> {
val rates = ratesResponse.data!!.conversion_rates
val rate = getRateForCurrency(toCurrency, rates)
if (rate==null){
_conversion.value= CurrencyEvent.Failure("Unexpected Error")
} else {
//val convertedCurrency = round(fromAmount * rate * 100)
_conversion.value= CurrencyEvent.Success(
"$fromAmount $fromCurrency = $toCurrency"
)
}
}
}
}
}
private fun getRateForCurrency(currency: String, rates: ConversionRates) = when (currency) {
"CAD" -> rates.CAD
"HKD" -> rates.HKD
"ISK" -> rates.ISK
"EUR" -> rates.EUR
"PHP" -> rates.PHP
"DKK" -> rates.DKK
"HUF" -> rates.HUF
"CZK" -> rates.CZK
"AUD" -> rates.AUD
"RON" -> rates.RON
"SEK" -> rates.SEK
"IDR" -> rates.IDR
"INR" -> rates.INR
"BRL" -> rates.BRL
"RUB" -> rates.RUB
"HRK" -> rates.HRK
"JPY" -> rates.JPY
"THB" -> rates.THB
"CHF" -> rates.CHF
"SGD" -> rates.SGD
"PLN" -> rates.PLN
"BGN" -> rates.BGN
"CNY" -> rates.CNY
"NOK" -> rates.NOK
"NZD" -> rates.NZD
"ZAR" -> rates.ZAR
"USD" -> rates.USD
"MXN" -> rates.MXN
"ILS" -> rates.ILS
"GBP" -> rates.GBP
"KRW" -> rates.KRW
"MYR" -> rates.MYR
else -> null
}}
CurrencyApi
interface CurrencyApi {
@GET("/v6/68c54e50f924117c29176f8f/latest/USD")
suspend fun getRates(
@Query("base_code") base_code : String
): Response<CurrencyResponse>}
Default Main Repo
class DefaultMainRepository @Inject constructor(
private val api :CurrencyApi): MainRepository {
override suspend fun getRates(base_code: String): Resource<CurrencyResponse> {
return try {
val response = api.getRates(base_code)
val result= response.body()
if (response.isSuccessful && result!=null){
Resource.Success(result)
} else{
Resource.Error(response.message())
}
}catch (e: Exception) {
Resource.Error(e.message?: "An error occured")
}
}}
MainRepo:
interface MainRepository {
suspend fun getRates(base_code: String) : Resource<CurrencyResponse>}
Upvotes: 0
Views: 364
Reputation: 156
Apperently, kotlin data classes can only contain about 127 arguments, so you have two options.
Break down the response data class into two (RatesAToL and RatesMToZ) and make two requests to the API.
Convert the JSON object (conversion_rates) into a list of objects
Rate(val code: String, val amount: Double)
. This can be done using a Moshi custom adapter.
See code gist here Custom Moshi adapter Full project on GitHub fxConverter
class MoshiJsonAdapter : JsonAdapter<InfoAndRatesResponse>() {
@FromJson
override fun fromJson(reader: JsonReader): InfoAndRatesResponse {
reader.beginObject()
var result = ""
var timeLastUpdateUnix = 0
var timeLastUpdateUtc = ""
var timeNextUpdateUnix = 0
var timeNextUpdateUtc = ""
var baseCode = ""
val rates = mutableListOf<Rate>()
while (reader.hasNext()) {
when (reader.nextName()) {
"result" -> result = reader.nextString()
"time_last_update_unix" -> timeLastUpdateUnix = reader.nextInt()
"time_last_update_utc" -> timeLastUpdateUtc = reader.nextString()
"time_next_update_unix" -> timeNextUpdateUnix = reader.nextInt()
"time_next_update_utc" -> timeNextUpdateUtc = reader.nextString()
"base_code" -> baseCode = reader.nextString()
"conversion_rates" -> {
reader.beginObject()
while (reader.peek() != JsonReader.Token.END_OBJECT) {
val code = reader.nextName()
val amount = when (code) {
baseCode -> reader.nextInt().toDouble()
else -> reader.nextDouble()
}
val infoBaseCode = baseCode
Timber.tag("MyTag")
.d(" code $code amount $amount infoBaseCode $infoBaseCode")
rates.add(
Rate(
code = code,
amount = amount,
infoBaseCode = infoBaseCode,
)
)
}
reader.endObject()
}
else -> reader.skipValue()
}
}
reader.endObject()
return InfoAndRatesResponse(
result = result,
timeLastUpdateUnix = timeLastUpdateUnix,
timeLastUpdateUtc = timeLastUpdateUtc,
timeNextUpdateUnix = timeNextUpdateUnix,
timeNextUpdateUtc = timeNextUpdateUtc,
baseCode = baseCode,
rates = rates
)
}
@ToJson
override fun toJson(writer: JsonWriter, value:
InfoAndRatesResponse?) {
throw UnsupportedOperationException()
}
}
Upvotes: 1
Reputation: 466
I'm not sure about this, but when it says "Unable to invoke no-arg constructor", to me that sounds like you need to be able to create an instance of CurrencyResponse
with no arguments. Maybe try setting some default values? I would give this a shot:
data class ConversionRates(
val AED: Double = 0.0,
val AFN: Double = 0.0,
val ALL: Double = 0.0,
val AMD: Double = 0.0,
val ANG: Double = 0.0,
val AOA: Double = 0.0,
val ARS: Double = 0.0,
val AUD: Double = 0.0,
val AWG: Double = 0.0,
val AZN: Double = 0.0,
val BAM: Double = 0.0,
val BBD: Double = 0.0,
val BDT: Double = 0.0,
val BGN: Double = 0.0,
val BHD: Double = 0.0,
val BIF: Double = 0.0,
val BMD: Double = 0.0,
val BND: Double = 0.0,
val BOB: Double = 0.0,
val BRL: Double = 0.0,
val BSD: Double = 0.0,
val BTN: Double = 0.0,
val BWP: Double = 0.0,
)
Upvotes: 0