Reputation: 295
I am using Volley to read a JSON API. Everything is working on that end. When I look at the arrival times that I get from the API there are varied which is what I would expect.
JSON Output
10-24 08:34:17.831 4671-4671/org.sherman.tony.nexttrain I/System.out: ARRIVAL TIME = 1508849280
10-24 08:34:17.831 4671-4671/org.sherman.tony.nexttrain I/System.out: ARRIVAL TIME = 1508850180
10-24 08:34:17.831 4671-4671/org.sherman.tony.nexttrain I/System.out: ARRIVAL TIME = 1508850600
10-24 08:34:17.831 4671-4671/org.sherman.tony.nexttrain I/System.out: ARRIVAL TIME = 1508848920
10-24 08:34:17.832 4671-4671/org.sherman.tony.nexttrain I/System.out: ARRIVAL TIME = 1508851500
10-24 08:34:17.832 4671-4671/org.sherman.tony.nexttrain I/System.out: ARRIVAL TIME = 1508851980
10-24 08:34:17.832 4671-4671/org.sherman.tony.nexttrain I/System.out: ARRIVAL TIME = 1508849340
10-24 08:34:17.832 4671-4671/org.sherman.tony.nexttrain I/System.out: ARRIVAL TIME = 1508850000
10-24 08:34:17.832 4671-4671/org.sherman.tony.nexttrain I/System.out: ARRIVAL TIME = 1508849760
10-24 08:34:17.832 4671-4671/org.sherman.tony.nexttrain I/System.out: ARRIVAL TIME = 1508849340
10-24 08:34:17.832 4671-4671/org.sherman.tony.nexttrain I/System.out: ARRIVAL TIME = 1508848680
10-24 08:34:17.832 4671-4671/org.sherman.tony.nexttrain I/System.out: ARRIVAL TIME = 1508850000
10-24 08:34:17.832 4671-4671/org.sherman.tony.nexttrain I/System.out: ARRIVAL TIME = 1508851980
My code adds the right number of elements to the ArrayList, but when I look at the data in the recycler it is multiple occurrences of the last element captured:
10-24 08:34:17.929 4671-4671/org.sherman.tony.nexttrain I/System.out: ARRIVAL TIME ===> 1508851980
10-24 08:34:17.932 4671-4671/org.sherman.tony.nexttrain I/System.out: ARRIVAL TIME ===> 1508851980
10-24 08:34:17.935 4671-4671/org.sherman.tony.nexttrain I/System.out: ARRIVAL TIME ===> 1508851980
10-24 08:34:17.940 4671-4671/org.sherman.tony.nexttrain I/System.out: ARRIVAL TIME ===> 1508851980
10-24 08:34:17.942 4671-4671/org.sherman.tony.nexttrain I/System.out: ARRIVAL TIME ===> 1508851980
10-24 08:34:17.945 4671-4671/org.sherman.tony.nexttrain I/System.out: ARRIVAL TIME ===> 1508851980
10-24 08:34:17.950 4671-4671/org.sherman.tony.nexttrain I/System.out: ARRIVAL TIME ===> 1508851980
10-24 08:34:17.954 4671-4671/org.sherman.tony.nexttrain I/System.out: ARRIVAL TIME ===> 1508851980
10-24 08:34:17.970 4671-4671/org.sherman.tony.nexttrain I/System.out: ARRIVAL TIME ===> 1508851980
This is the heart of my Activity Code:
// Get a list of train schedules
//
listOfTrains = ArrayList<TrainStatus>()
volleyRequest = Volley.newRequestQueue(this)
readTrains(url,station)
}
fun readTrains(url:String, station: String) {
var listOfTrains = ArrayList<TrainStatus>()
var trainStatus = TrainStatus()
println("URL ===> $url")
val jsonObjectRequest = JsonObjectRequest(Request.Method.GET,url,
Response.Listener {
response: JSONObject ->
try {
val responseMode = response.getJSONArray("mode")
val responseModeRouteObj = responseMode.getJSONObject(0)
val responseModeRouteObjRoute = responseModeRouteObj.getJSONArray("route")
for (i in 0..responseModeRouteObjRoute.length() - 1){
val responseModeRouteObjRouteRouteObj = responseModeRouteObjRoute.getJSONObject(i)
val responseModeRouteObjRouteRouteObjDirection = responseModeRouteObjRouteRouteObj.getJSONArray("direction")
for (j in 0.. responseModeRouteObjRouteRouteObjDirection.length() - 1){
val responseModeRouteObjRouteRouteObjDirectionDirectionObj = responseModeRouteObjRouteRouteObjDirection.getJSONObject(j)
val direction = responseModeRouteObjRouteRouteObjDirectionDirectionObj.getString("direction_id")
trainStatus.direction_id = direction.toInt()
val tripArray = responseModeRouteObjRouteRouteObjDirectionDirectionObj.getJSONArray("trip")
for (k in 0..tripArray.length() - 1){
var tripArrayObj = tripArray.getJSONObject(k)
var schArrival = tripArrayObj.getString("sch_arr_dt")
trainStatus.sch_arr_time = schArrival.toLong()
trainStatus.station = station
println("ARRIVAL TIME = ${trainStatus.sch_arr_time}") // DEBUGGING print statement
listOfTrains!!.add(trainStatus)
}
}
}
trainAdapter = TrainListAdapter(listOfTrains, this)
layoutManager = LinearLayoutManager(this)
// Set up recycler Adapter
recyclerViewID.layoutManager = layoutManager
recyclerViewID.adapter = trainAdapter
trainAdapter!!.notifyDataSetChanged()
} catch (e: JSONException){e.printStackTrace()}
},
Response.ErrorListener {
error: VolleyError? ->
try{
error!!.printStackTrace()
}catch(e:JSONException) {
e.printStackTrace()
}
})
//val list:ArrayList<TrainList>? = null
volleyRequest!!.add(jsonObjectRequest)
println("SIZE OF ARRAY ===> ${listOfTrains.size}")
return
//return list
}
And this is my Adapter Code:
package org.sherman.tony.nexttrain.adapters
import android.content.Context
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import org.sherman.tony.nexttrain.models.TrainStatus
import org.sherman.tony.nexttrain.R
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.*
class TrainListAdapter(var listOfTrains: ArrayList<TrainStatus>,
val context: Context): RecyclerView.Adapter<TrainListAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup?, position: Int): ViewHolder {
val view = LayoutInflater.from(context)
.inflate(R.layout.station_lst_item, parent, false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return listOfTrains.size
}
override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
holder!!.bindView(listOfTrains[position])
}
inner class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
var station = itemView.findViewById<TextView>(R.id.stationListTextViewID)
var arrivalTime = itemView.findViewById<TextView>(R.id.timeScheduleID)
fun bindView(train: TrainStatus){
var humanTime = readableTime(train.sch_arr_time!!)
println("ARRIVAL TIME ===> ${train.sch_arr_time}")
station.text = train.station.toString()
//arrivalTime.text = humanTime
arrivalTime.text = train.sch_arr_time.toString()
}
fun readableTime(milliSeconds: Long): String {
var date = Date(milliSeconds)
val dateFormat: DateFormat = SimpleDateFormat("H:mm")
return dateFormat.format(date)
}
}
}
How do I get the adapter to add the actual returned vales instead of multiple copies of the last element.
Thank you.
Upvotes: 1
Views: 1813
Reputation: 472
Think i found out the problem. You are creating a list of TrainStatus and you get that list from a remote API. For each call you iterate and add the result given. The problem lies in the declaration of the variable trainStatus.
You do a var trainStatus = TrainStatus() outside the function readTrains and then, on each iteration, you change the value of that variable and add it to the list.
You do so but you don't create a new instance for each TrainStatus you want to add, so you add every time the same instance of the same object to your list just changing the value in it. This way, each element of the list point to the same object TrainStatus, that hold the value of the last element received from your request.
To fix the proble simply create a new instance every time you star a new iteration.
So change your code to:
for (i in 0..responseModeRouteObjRoute.length() - 1){
val responseModeRouteObjRouteRouteObj = responseModeRouteObjRoute.getJSONObject(i)
val responseModeRouteObjRouteRouteObjDirection = responseModeRouteObjRouteRouteObj.getJSONArray("direction")
for (j in 0.. responseModeRouteObjRouteRouteObjDirection.length() - 1){
val responseModeRouteObjRouteRouteObjDirectionDirectionObj = responseModeRouteObjRouteRouteObjDirection.getJSONObject(j)
val direction = responseModeRouteObjRouteRouteObjDirectionDirectionObj.getString("direction_id")
val tripArray = responseModeRouteObjRouteRouteObjDirectionDirectionObj.getJSONArray("trip")
for (k in 0..tripArray.length() - 1){
trainStatus.direction_id = TrainStatus()
trainStatus.direction_id = direction.toInt()
var tripArrayObj = tripArray.getJSONObject(k)
var schArrival = tripArrayObj.getString("sch_arr_dt")
trainStatus.sch_arr_time = schArrival.toLong()
trainStatus.station = station
println("ARRIVAL TIME = ${trainStatus.sch_arr_time}") // DEBUGGING print statement
listOfTrains!!.add(trainStatus)
}
}
}
I'd also suggest you to not create a new instance of the adapter for each call you do but to keep the list of trainstatus in the adapter directly
Upvotes: 1