Hi and thanks for reading in advance, I have built a small project testing an adapter to populate a main activity view with a custom xml template [this template holds some fields that are populated by some simple test data and images inside the project] The build is fine afaik, I have debugged it as best I can to yield no errors and I cant actually find the error as i follow the build in debug so it's likely my noob-like experience with kotlin, android studio and maybe the later development approach changes. My best guess after following it through a few (way more ha) times, at this stage it seemed to be going wrong during the android part of the build versus any prep and adapter code so it could be some settings I havent invoked maybe... Also probably importantly: I saw it pull in the recyclerView during debug(prior to any customisation from the imported xml layout im using), the visual then disappears, but i do see all the code being populated by the functions ive created in MainActivity and the adapter does seem to return to MainActivity with the respective data constructed. I enclose the project zipped as there is no discernable error code or post runtime exit code that i can find [thats not to say there isn't one, I'm newoob to the IDE :( ] I'm targeting an Android 7.0 600*1024 mdpi using API 24 on a 7" (LH flip)portrait orientation x86 emulator
I'm using Android Studio 2021.1.1 patch 3 if that's important to know too
Thanks again for anyone who can take a peek at it to help me along, im proper stuck, been so for couple days now, thinking of a complete redo again :/ :) I enclose a link to the zipped file below [due to no errors in debug to provide here]
[Edit: Cripes I forgot to mention I'm also using CircleImageViewer, not sure if that causing an issue but it doesn't appear to be ]
CodePudding user response:
I took a look at you app, the error it is throwing (look in the Logcat tab!) is this
Process: com.example.kayakthing, PID: 4289
java.lang.IndexOutOfBoundsException: Index: 5, Size: 5
at java.util.ArrayList.get(ArrayList.java:411)
at com.example.kayakthing.HiresAdapter.onBindViewHolder(HiresAdapter.kt:34)
at com.example.kayakthing.HiresAdapter.onBindViewHolder(HiresAdapter.kt:11)
Problem
The reason it is throwing this is because you are supplying different length arrays to your adapter. Take a look at the adapter code below - in your current code the lengths of nameList
and clientDetailsList
are both 7 but the length of hireImageList
is 5. Since you define getItemCount
based on the length of nameList
- the adapter crashes when trying to show values for positions past the end of the hireImageList
size.
override fun onBindViewHolder(holder: HiresViewHolder, position: Int) {
holder.tvClientName.text = nameList[position]
holder.tvClientDetails.text = clientDetailsList[position]
holder.imageView.setImageResource(hireImageList[position])
}
override fun getItemCount(): Int {
return nameList.size
}
Solution
I recommend you 1) learn to read the Logcat tab to find errors, and 2) define a data class to hold the three items you need in your adapter, so you can pass in a single list of that data class instead of three lists. That way there is no way to pass in lists with mis-matched lengths.
For example, use something like this and have the adapter take a single List<HiresAdapter.Data>
instead of three lists.
class HiresAdapter(
private var adapterData: ArrayList<Data>,
private var context: Context) : RecyclerView.Adapter<HiresAdapter.HiresViewHolder>() {
// Define a data class in the adapter to hold the data
// needed for each row
data class Data(val name: String, val details: String, val image: Int)
class HiresViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var tvClientName : TextView = itemView.findViewById(R.id.tvClientName)
var tvClientDetails : TextView = itemView.findViewById(R.id.tvClientDetail)
var imageView : CircleImageView = itemView.findViewById(R.id.hireImageView)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) : HiresViewHolder {
this.context = parent.context
val view : View = LayoutInflater.from(this.context).inflate(R.layout.rv_card_design,parent, false)
return HiresViewHolder(view)
}
override fun onBindViewHolder(holder: HiresViewHolder, position: Int) {
holder.tvClientName.text = adapterData[position].name
holder.tvClientDetails.text = adapterData[position].details
holder.imageView.setImageResource(adapterData[position].image)
}
override fun getItemCount(): Int {
return adapterData.size
}
}
and populate it like this
val adapterData = ArrayList<HiresAdapter.Data>()
adapterData.add(HiresAdapter.Data("Geoff", "Geoff", R.drawable.solo))
adapterData.add(HiresAdapter.Data("Frogme", "Frogme", R.drawable.tandem))
adapterData.add(HiresAdapter.Data("Jenny", "Jenny", R.drawable.quattro))
adapterData.add(HiresAdapter.Data("Benny", "Benny", R.drawable.sup))
adapterData.add(HiresAdapter.Data("Sylvia", "Sylvia", R.drawable.croc))
adapter = HiresAdapter(adapterData, this@MainActivity)