'How to get openweathermap icon from OneCall API nested-list?
I'm adding weather forecast data to my app. The info displays in a RecyclerView after it is received by an API call using Retrofit 2. I'm having trouble getting the icon string id.
Here is the JSON response.
{"lat": 33.44, "lon": -94.04, "timezone": "America/Chicago", "timezone_offset": -21600, "daily": [ { "dt": 1618308000, "sunrise": 1618282134, "sunset": 1618333901, "moonrise": 1618284960, "moonset": 1618339740, "moon_phase": 0.04, "temp": { "day": 279.79, "min": 275.09, "max": 284.07, "night": 275.09, "eve": 279.21, "morn": 278.49 }, "feels_like": { "day": 277.59, "night": 276.27, "eve": 276.49, "morn": 276.27 }, "pressure": 1020, "humidity": 81, "dew_point": 276.77, "wind_speed": 3.06, "wind_deg": 294, "weather": [ { "id": 500, "main": "Rain", "description": "light rain", "icon": "10d" } ], "clouds": 56, "pop": 0.2, "rain": 0.62, "uvi": 1.93 }]}
I'm making the call and getting the callback. I'm getting the temp and the other info I need for the forecast data. I'm not sure how I can access the icon id in the nested list. Here is how I'm getting the response.
private fun loadWeather() {
loadWeatherData()
Log.d("weatherCall", "loadWeather ran")
rvWeather?.layoutManager = LinearLayoutManager(this)
rvWeather?.adapter = weatherAdapter
}
private fun loadWeatherData() {
val un = "imperial"
val wKey = "key"
val lastUserLatLng = latLng
val locationLatLng = lastUserLatLng.split(", ").toTypedArray()
val locationLatitude = locationLatLng[0]
val locationLongitude = locationLatLng[1]
val baseURL = "https://api.openweathermap.org/"
Log.d("weatherCall", "baseURL: $baseURL")
val retro = Retrofit.Builder()
.baseUrl(baseURL)
.addConverterFactory(GsonConverterFactory.create())
.build()
val api = retro.create(ApiCallService::class.java)
api.fetchAllData(locationLatitude, locationLongitude, un, wKey).enqueue(object : Callback<WeatherResponse> {
override fun onResponse(
call: Call<WeatherResponse>,
response: Response<WeatherResponse>
) {
if(response.isSuccessful) {
val da = response.body()!!.daily
weatherAdapter.dailyList = da
weatherAdapter.notifyDataSetChanged()
}
}
override fun onFailure(call: Call<WeatherResponse>, t: Throwable) {
Log.d("weatherCall", "fetch onFail ran response: $t")
rvWeather?.gone()
}
})
}
I save the ArrayList to the List for the RecyclerviewAdapter.
Here is the interface:
interface ApiCallService {
@GET("data/2.5/onecall?")
fun fetchAllData(@Query("lat") lat: String, @Query("lon") lon: String, @Query("units") units: String, @Query("appid") appId: String): Call<WeatherResponse>
}
I'm using the OneCall API which brings back all the info I need in just the one call. the response is like this:
data class WeatherResponse(
val lat: Number,
val lon: Number,
val timezone: String,
val timezone_offset: Number,
val current: CurrentList,
val minutely: ArrayList<Minutely>,
val hourly: ArrayList<Hourly>,
val daily: ArrayList<DailyList>,
val alerts: ArrayList<AlertsList>
)
I get the temperature from the TempList and I need to access the weather: ArrayList to grab the weather icon id, here is the DailyList
data class DailyList(
val dt: Number,
val moon_phase: Number,
val moonrise: Number,
val moonset: Number,
val sunrise: Number,
val sunset: Number,
val temp: TempList,
val feels_like: FeelsList,
val pressure: Number,
val humidity: Number,
val dew_point: Number,
val wind_speed: Number,
val wind_deg: Number,
val weather: ArrayList<DailyWeatherList>,
val clouds: Number,
val pop: Number,
val rain: Number,
val snow: Number,
val uvi: Number)
and here is the ArrayList:
data class DailyWeatherList(
val description: String,
val icon: String,
val id: Number,
val main: String)
Here is my rv adapter class:
class WeatherForecastAdapter(var dailyList: List<DailyList>): RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun getItemCount(): Int {
return dailyList.size
}
class WeatherForecastViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){
fun bind(postModel: DailyList) {
val tvDayOfWeek = itemView.findViewById<TextView>(R.id.tvDayOfWeek)
val tvDateOfMonth = itemView.findViewById<TextView>(R.id.tvDateOfMonth)
val tvTemp = itemView.findViewById<TextView>(R.id.tvTemp)
val ivWeatherIcon = itemView.findViewById<ImageView>(R.id.ivWeatherIcon)
val iconURL = postModel.weather[position].icon
val tem = postModel.temp.max // I originally tried this same code block here in the fun bind, but I couldnt get the position, always a crash. I used absoluteAdapterPosition, and bindingAdapterPosition but they both crash the app
val userImage = "http://openweathermap.org/img/wn/[email protected]"
tvTemp.text = tem.toString()
Glide.with(itemView).load(userImage).into(ivWeatherIcon)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
Log.d("weatherCall", "onCreateViewHolder ran")
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.weather_forecast_card, parent, false)
return WeatherForecastViewHolder(view)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
(holder as WeatherForecastViewHolder).bind(dailyList[position])
-- moving the code to the onBineViewHolder I thought I would be able use the position here but no luck.
val tvDayOfWeek = holder.itemView.findViewById<TextView>(R.id.tvDayOfWeek)
val tvDateOfMonth = holder.itemView.findViewById<TextView>(R.id.tvDateOfMonth)
val tvTemp = holder.itemView.findViewById<TextView>(R.id.tvTemp)
val ivWeatherIcon = holder.itemView.findViewById<ImageView>(R.id.ivWeatherIcon)
val iconURL = dailyList[position]
iconURL.weather[position].icon
val tem = dailyList[position].temp.max
val userImage = "http://openweathermap.org/img/wn/[email protected]"
tvTemp.text = tem.toString()
Glide.with(holder.itemView).load(userImage).into(ivWeatherIcon)
}}
The position works for the primary list, but not for the nested list. This works fine for the temp:
val tem = dailyList[position].temp.max
but this doesnt work to get the "icon":
val iconURL = dailyList[position]
iconURL.weather[position].icon
How can I access the inner ArrayList with the correct position? Is there a better way of saving the main list so that I can access the nested-lists?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|