I'm trying to get some results from json but i have a problem.When i have only this line of code it works and i can get the temperature
var main: TemperatureData? = null
but i want also to get more values from my json so i insert this line of code
var weather: WeatherDataJson? = null
When i'm adding the second line it doesn't fetch any data(it even stops fetching the var main:... data)
This is my weather data class
class WeatherData {
var main: TemperatureData? = null
var weather: WeatherDataJson? = null
}
here is my interface class
interface ApiInterface {
#GET("data/2.5/weather?q=Prague")
fun getWeatherData(#Query("appid") appId: String)
: Call<WeatherData>
}
My TemperatureData class
data class TemperatureData(var temp: String)
And my WeatherDataJson class
data class WeatherDataJson(var description:String)
In my mainclass i have a function to show the json into my screen but i can't load the "var weather..."
Here is the function
private fun getTemperatureData(repository: Repository) {
repository.getApiInterface()
.getWeatherData("4cf7f6610d941a1ca7583f50e7e41ba3")
.enqueue(object : Callback<WeatherData> {
override fun onFailure(call: Call<WeatherData>?, t: Throwable?) {
t?.printStackTrace()
}
override fun onResponse(call: Call<WeatherData>?, response: Response<WeatherData>?) {
val weatherData: WeatherData? = response?.body()
weatherData?.let {
it.main?.let {
tempText.text = it.temp
}
it.weather?.let{
weatherTextFromApi.text=it.description
}
}
}
})
}
On the description is says unresolved reference description
If you use openweathermap api declare those data classes
data class WeatherData(
#SerializedName("coord") val coord: Coord,
#SerializedName("weather") val weather: List<Weather>,
#SerializedName("base") val base: String,
#SerializedName("main") val main: TemperatureData,
#SerializedName("visibility") val visibility: Int,
#SerializedName("wind") val wind: Wind,
#SerializedName("clouds") val clouds: Clouds,
#SerializedName("dt") val dt: Int,
#SerializedName("sys") val sys: Sys,
#SerializedName("id") val id: Int,
#SerializedName("name") val name: String,
#SerializedName("cod") val cod: Int
)
data class Sys(
#SerializedName("type") val type: Int,
#SerializedName("id") val id: Int,
#SerializedName("message") val message: Double,
#SerializedName("country") val country: String,
#SerializedName("sunrise") val sunrise: Int,
#SerializedName("sunset") val sunset: Int
)
data class Coord(
#SerializedName("lon") val lon: Double,
#SerializedName("lat") val lat: Double
)
data class TemperatureData(
#SerializedName("temp") val temp: Double,
#SerializedName("pressure") val pressure: Int,
#SerializedName("humidity") val humidity: Int,
#SerializedName("temp_min") val tempMin: Double,
#SerializedName("temp_max") val tempMax: Double
)
data class Weather(
#SerializedName("id") val id: Int,
#SerializedName("main") val main: String,
#SerializedName("description") val description: String,
#SerializedName("icon") val icon: String
)
data class Clouds(
#SerializedName("all") val all: Int
)
data class Wind(
#SerializedName("speed") val speed: Double,
#SerializedName("deg") val deg: Int
)
if you goal is get description from weather all you need will be
weatherData.weather.firstOrNull()?. description ?: ""
For getting url of icon
It is kind of tricky, you could get url from response but only url of icon.
val iconId = weatherData.weather.firstOrNull()?. description
val iconUrl = iconId?.let{"http://openweathermap.org/img/w/${it}.png"} ?: ""
After that you should use Glide library or Picasso for loading imageUrl to ImageView
See more about Glide here https://github.com/bumptech/glide
The server response from OpenWeatherMap is returning a JSON array, not a JSON object, for weather. Gson/Retrofit cannot automatically turn an array into a single Object, so you need to change your data class to hold a List (or use a custom Gson deserializer and manually grab the item you want from the array).
Example of what your top level class should be:
class WeatherData {
var main: TemperatureData? = null
var weather: List<WeatherDataJson>? = null
}
Related
need help in parsing this json file from this endpoint
http://ergast.com/api/f1/constructors
this is my data class
data class Teams(
val MRData: MRdata
){
data class MRdata(
val ConstructorTable: ConstructorsTable,
val limit: String,
val offset: String,
val series: String,
val total: String,
val url: String,
val xmlns: String
){
data class ConstructorsTable(
val Constructors: List<Constructor>?
) {
data class Constructor(
val constructorId: String?,
val name: String?,
val nationality: String?,
val url: String?
)
}
}
}
when i use Teams class as a return model it logs actual data but, when i try to return specific data like constructorID or nationality it returns null.
Here is my entity class:
#Entity
data class User(
#PrimaryKey
#Json(name = "id") val userId: String,
#Json(name = "login") val userName: String,
#Json(name = "avatar_url") val userAvatar: String,
val profile: Profile? = null
) : Serializable
Here is my Profile data class
data class Profile(
val avatar_url: String,
val bio: String,
val blog: String,
val company: Any,
val created_at: String,
val email: Any,
val events_url: String,
val followers: Int,
val followers_url: String,
val following: Int,
val following_url: String,
val gists_url: String,
val gravatar_id: String,
val hireable: Boolean,
val html_url: String,
val id: Int,
val location: String,
val login: String,
val name: String,
val node_id: String,
val organizations_url: String,
val public_gists: Int,
val public_repos: Int,
val received_events_url: String,
val repos_url: String,
val site_admin: Boolean,
val starred_url: String,
val subscriptions_url: String,
val twitter_username: Any,
val type: String,
val updated_at: String,
val url: String
) : Serializable
but every time I try to insert data into the table I am getting the error, how can I insert null data object in table while using room database?
The issue here is that Room doesn't know how to insert attribute of type Profile to the table.
The simple solution would be to use a type converter. Something like the following:
class DatabaseConverters {
#TypeConverter
fun toProfile(profileJson: String): Profile? {
return <Create a Profile object out of a JSON string>
}
#TypeConverter
fun fromProfile(profile: Profile?): String {
return <JSON string representation of Profile object>
}
}
In your case - you can use "" (empty string) when Profile is null.
More info about converters: Here
I'm trying to create a request using Retrofit2 in Kotlin and my Json data looks like this:
{
"actionRights": [
{
"hasArticlePriceChangeRights": false,
"hasStockLevelViewRights": false
}
],
"stats": {
"errors": 12,
"warnings": 21,
"outOfOrder": 58,
"running": 42
},
"markers": []
}
I need to get the "stats" data from my response.
How is my model class look like? I tried something but I get this error.
Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $
EDIT: I created this ModelClass and I'm still getting this error:
Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $
data class StatsModel(
#SerializedName("actionRights") val actionRights : List<ActionRights>,
#SerializedName("stats") val stats : Stats,
#SerializedName("markers") val markers : List<Markers>
) {
data class ActionRights (
#SerializedName("hasArticlePriceChangeRights") val hasArticlePriceChangeRights : Boolean,
#SerializedName("hasStockLevelViewRights") val hasStockLevelViewRights : Boolean
)
data class Stats (
#SerializedName("errors") val errors : Int,
#SerializedName("warnings") val warnings : Int,
#SerializedName("outOfOrder") val outOfOrder : Int,
#SerializedName("running") val running : Int
)
data class Markers (
#SerializedName("deviceGuid") val deviceGuid : String,
#SerializedName("lat") val lat : Double,
#SerializedName("lng") val lng : Double,
#SerializedName("title") val title : Int,
#SerializedName("city") val city : String,
#SerializedName("street") val street : Int,
#SerializedName("serialNumber") val serialNumber : Int,
#SerializedName("LastStatusMessageDateTime") val lastStatusMessageDateTime : String,
#SerializedName("LastStatusMessageBitSet_0_63") val lastStatusMessageBitSet_0_63 : Int,
#SerializedName("LastStatusMessageBitSet_64_127") val lastStatusMessageBitSet_64_127 : Int,
#SerializedName("ActionsStatus") val actionsStatus : Int,
#SerializedName("SpareColumn1") val spareColumn1 : String,
#SerializedName("SpareColumn2") val spareColumn2 : String,
#SerializedName("SpareColumn3") val spareColumn3 : String,
#SerializedName("SpareColumn4") val spareColumn4 : String,
#SerializedName("SpareColumn5") val spareColumn5 : String,
#SerializedName("SpareColumn6") val spareColumn6 : String,
#SerializedName("SpareColumn7") val spareColumn7 : String,
#SerializedName("SpareColumn8") val spareColumn8 : String,
#SerializedName("SpareColumn9") val spareColumn9 : String,
#SerializedName("SpareColumn10") val spareColumn10 : String,
#SerializedName("EstimatedDeliveryDateTime") val estimatedDeliveryDateTime : String,
#SerializedName("IpAddress") val ipAddress : String,
#SerializedName("Active") val active : Int,
#SerializedName("ParentAreaGuid") val parentAreaGuid : String,
#SerializedName("AreaGuid") val areaGuid : String,
#SerializedName("TariffGroupGuid") val tariffGroupGuid : String,
#SerializedName("DeviceType") val deviceType : String,
#SerializedName("EstimateArticleName") val estimateArticleName : String,
#SerializedName("EstimateArticleGuid") val estimateArticleGuid : String,
#SerializedName("lastCoinboxExchange") val lastCoinboxExchange : String,
#SerializedName("lastStatusUpdateTime") val lastStatusUpdateTime : String,
#SerializedName("reportDateTime") val reportDateTime : String,
#SerializedName("hasFinancialInfo") val hasFinancialInfo : Boolean,
#SerializedName("ticketsSold") val ticketsSold : Int,
#SerializedName("cash") val cash : Int,
#SerializedName("cashless") val cashless : Int,
#SerializedName("hasStockLevel") val hasStockLevel : Boolean,
#SerializedName("hasArticlePrices") val hasArticlePrices : Boolean,
#SerializedName("EstDeliveryDays") val estDeliveryDays : String,
#SerializedName("hasOther") val hasOther : Boolean,
#SerializedName("hasOutOfOrder") val hasOutOfOrder : Boolean,
#SerializedName("hasWarning") val hasWarning : Boolean,
#SerializedName("hasError") val hasError : Boolean,
#SerializedName("flags") val flags : List<Flags>,
#SerializedName("actionState") val actionState : String,
#SerializedName("spareColumns") val spareColumns : List<SpareColumns>
)
data class Flags (
#SerializedName("ErrorLevel") val errorLevel : Int,
#SerializedName("ErrorFlag") val errorFlag : Int,
#SerializedName("Translation") val translation : String,
#SerializedName("BitPosition") val bitPosition : Int
)
data class SpareColumns (
#SerializedName("key") val key : String,
#SerializedName("value") val value : String
)
}
And I'm processing the response like this:
fun getStatusService(mandatorGuid: String, #Nullable statusCallbacks: ChartsCallbacks.StatsCallbacks) {
val mandatorItem = MandatorItem(mandatorGuid)
val guid: MutableMap<String, String> = HashMap()
guid["guid"] = mandatorItem.guid
var statusData: StatsModel.Stats
val call: Call<StatsModel> = createAPI().getStatus(mandatorItem.guid)
call.enqueue(object : Callback<StatsModel> {
override fun onFailure(call: Call<StatsModel>, t: Throwable) {
Log.i("TEST", "Status failure: $t")
}
override fun onResponse(call: Call<StatsModel>, response: Response<StatsModel>) {
if (response.isSuccessful) {
Log.i("TEST", "ITEM " + response.headers().toString())
statusData = response.body()!!.stats
Log.i("TEST", "ITEM $statusData")
statusCallbacks.onSuccess(statusData)
}
}
})
}
data class ActionRight(
val hasArticlePriceChangeRights: Boolean?=null,
val hasStockLevelViewRights: Boolean?=null
)
this is for state
data class Stats(
val errors:Int? = null,
val warnings? = null,
val outOfOrder? = null,
val running? = null
)
call this model into your retrofit you got only your state
data class StatsModel(
val actionRights: ArrrayList<ActionRight>?=null,
val markers: ArrrayList<Any>?=null,
val stats: Stats? = null)
Your main model:
data class MyModel(
val actionRights: List<ActionRight?>?,
val markers: List<Marker?>?,
val stats: Stats?
)
Your Sub Models:
data class ActionRight(
val hasArticlePriceChangeRights: Boolean?,
val hasStockLevelViewRights: Boolean?
)
data class Marker(
val test1: Int?,
val test2: String?
)
data class Stats(
val errors: Int?,
val outOfOrder: Int?,
val running: Int?,
val warnings: Int?
)
I create a fake Marker class because I don't know your full json data.
You should modelling Marker class for according your json data. You can call MyModel class from retrofit.
Edit Response (Only parse Stats class)
This class represent parse only Stats class, you can call from retrofit. #JsonIgnoreProperties should ignore other data.
#JsonIgnoreProperties(ignoreUnknown = true)
data class MyModel(
#JsonProperty("stats")
val stats: Stats?
)
#JsonIgnoreProperties(ignoreUnknown = true)
data class Stats(
#JsonProperty("errors")
val errors: Int?,
#JsonProperty("outOfOrder")
val outOfOrder: Int?,
#JsonProperty("running")
val running: Int?,
#JsonProperty("warnings")
val warnings: Int?
)
Note: The code use Jackson library.
implementation 'com.squareup.retrofit2:converter-jackson:2.5.0'
I'm doing weather app in Kotlin, and in Activity is method which firstly takes cache data from Room, and after one hour data is updated. But there is problem probably with saving of data in database. I checked API logs in Profiles and there is no null with Weather List, so API works fine.
I'm trying to save Weather list as an ArrayList, but the answer from logs is still null. I also tried Type Converter, but still nothing. Maybe someone will find the reason for my problem and the answer.
EDIT: I removed #Embedded(prefix = "weather_") above the ArrayList and it works.
CurrentWeather (stores Weather ArrayList):
#Entity(tableName = "current_weather")
data class CurrentWeather(
#Embedded(prefix = "weather_")
val weather: ArrayList<Weather>? = ArrayList(), //here is my problem
#SerializedName("base")
val base: String,
#Embedded(prefix = "clouds_")
val clouds: Clouds,
#SerializedName("cod")
val cod: Int,
#Embedded(prefix = "coord_")
val coord: Coord,
#SerializedName("dt")
val dt: Int,
#SerializedName("id")
val id: Int,
#Embedded(prefix = "main_")
val main: Main,
#SerializedName("name")
val name: String,
#Embedded(prefix = "sys_")
val sys: Sys,
#SerializedName("visibility")
val visibility: Int,
#Embedded(prefix = "wind_")
val wind: Wind
) {
#PrimaryKey(autoGenerate = false)
var idKey: Int = CURRENT_WEATHER_ID
}
Weather:
data class Weather(
#SerializedName("description")
val description: String,
#SerializedName("icon")
val icon: String,
#SerializedName("id")
val id: Int,
#SerializedName("main")
val main: String
)
Converter:
class Converters {
#TypeConverter
fun arrayListToJson(value: List<Weather>?): String {
return Gson().toJson(value)
}
#TypeConverter
fun jsonToArrayList(value: String): List<Weather> {
val objects = Gson().fromJson(value, Array<Weather>::class.java) as Array<Weather>
val list = objects.toList()
return list
}
Database:
#Database(entities = [CurrentWeather::class, Location::class], version = 15, exportSchema = false)
#TypeConverters(Converters::class) //converter initialization
abstract class WeatherDatabase : RoomDatabase() {
Here is the modified converter class. It might help you.
object class Converters {
val gson = Gson()
#TypeConverter
fun arrayListToJson(list: List<Weather>?): String? {
return if(list == null) null else gson.toJson(list)
}
#TypeConverter
fun jsonToArrayList(jsonData: String?): List<Weather>? {
return if (jsonData == null) null else gson.fromJson(jsonData, object : TypeToken<List<Weather>?>() {}.type)
}
}
I'm having an issue.I have project and then i copy paste into an other new project and i'm facing this error
No type arguments expected for class Call
In the first project i didn't have any problem...
Here is my interface class which i have the error
interface ApiInterface {
#GET("data/2.5/weather?q=Prague")
fun getWeatherData(#Query("units") units: String,
#Query("appid") appId: String)
:Call<WeatherData> //here is the error
}
and here is my WeatherData class
data class WeatherData(
#SerializedName("coord") val coord: Coord,
#SerializedName("weather") val weather: List<Weather>,
#SerializedName("base") val base: String,
#SerializedName("main") val main: TemperatureData,
#SerializedName("visibility") val visibility: Int,
#SerializedName("wind") val wind: Wind,
#SerializedName("clouds") val clouds: Clouds,
#SerializedName("dt") val dt: Int,
#SerializedName("sys") val sys: Sys,
#SerializedName("id") val id: Int,
#SerializedName("name") val name: String,
#SerializedName("cod") val cod: Int
)
data class Sys(
#SerializedName("type") val type: Int,
#SerializedName("id") val id: Int,
#SerializedName("message") val message: Double,
#SerializedName("country") val country: String,
#SerializedName("sunrise") val sunrise: Int,
#SerializedName("sunset") val sunset: Int
)
data class Coord(
#SerializedName("lon") val lon: Double,
#SerializedName("lat") val lat: Double
)
data class TemperatureData(
#SerializedName("temp") val temp: Double,
#SerializedName("pressure") val pressure: Int,
#SerializedName("humidity") val humidity: Int,
#SerializedName("temp_min") val tempMin: Double,
#SerializedName("temp_max") val tempMax: Double
)
data class Weather(
#SerializedName("id") val id: Int,
#SerializedName("main") val main: String,
#SerializedName("description") val description: String,
#SerializedName("icon") val icon: String
)
data class Clouds(
#SerializedName("all") val all: Int
)
data class Wind(
#SerializedName("speed") val speed: Double,
#SerializedName("deg") val deg: Int
Just verify that you've imported the correct package from Retrofit.
The correct one is
retrofit2.Call
not to be confused with, for example
android.telecom.Call
If you import both Retrofit and Okhttp, make sure the Call class you use is the one from Retrofit:
import retrofit2.Call
not:
import okhttp3.Call
Give a look to import section and check whether retrofit2.Call library is imported or not ,sometimes it gets touched with okhttp3.call but you have to use the retrofit one.so make sure the library is imported to the interface/class.