I don’t understand why the list is not filled with the help of a custom adapter. Only the last element from the array gets into textView (textHeroView). And it turns out that the ListView does not go as a list, but simply with one item from the array. I tried to put it on a separate list, to no avail. Can you please tell me what I made a mistake?
HeroesAdapter
class HeroesAdapter(context: Context, heroes: List<TestHero>): BaseAdapter() {
private val context = context
private val heroes = heroes
override fun getCount(): Int {
return heroes.count()
}
override fun getItem(position: Int): Any {
return heroes[position]
}
override fun getItemId(position: Int): Long {
return 0
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
// categoryView = LayoutInflater.from(context).inflate(R.layout.activity_heroes, null)
val listheroView = LayoutInflater.from(context).inflate(R.layout.list_hero_view, parent, false)
// val categoryImage: ImageView = categoryView.findViewById(R.id.heroesImageView)
val heroText: TextView = listheroView.findViewById(R.id.textHeroView)
val category = heroes[position]
// heroText.text = category.legends.all.keys.first()
for((key) in category.legends.all){
Log.d("HeroesActivity", key)
heroText.text = key
}
return listheroView
}
}
list_hero_view
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ImageView
android:id="@+id/heroesImageView"
android:layout_width="426dp"
android:layout_height="180dp"
android:layout_marginTop="24dp"
android:scaleType="centerCrop"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.533"
app:layout_constraintStart_toStartOf="parent"
app:srcCompat="@mipmap/wraith_apex_legends" />
<TextView
android:id="@+id/textHeroView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Wraith"
android:textColor="@android:color/darker_gray"
android:textSize="54sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@+id/heroesImageView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.12"
app:layout_constraintStart_toStartOf="@+id/heroesImageView"
app:layout_constraintTop_toTopOf="@+id/heroesImageView"
app:layout_constraintVertical_bias="0.04000002" />
</androidx.constraintlayout.widget.ConstraintLayout>
activity_heroes
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".HeroesActivity">
<ImageView
android:id="@+id/imageView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="2dp"
android:layout_marginTop="2dp"
android:layout_marginBottom="24dp"
app:layout_constraintBottom_toTopOf="@+id/heroesListView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@mipmap/ic_launcher_round" />
<ListView
android:id="@+id/heroesListView"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_marginStart="1dp"
android:layout_marginTop="100dp"
android:layout_marginEnd="1dp"
android:layout_marginBottom="1dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textNickname"
android:layout_width="251dp"
android:layout_height="29dp"
android:layout_marginStart="40dp"
android:layout_marginEnd="279dp"
android:layout_marginBottom="60dp"
android:text="Nickname"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/heroesListView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.145"
app:layout_constraintStart_toEndOf="@+id/imageView2"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.272" />
<TextView
android:id="@+id/textLvl"
android:layout_width="111dp"
android:layout_height="19dp"
android:layout_marginEnd="28dp"
android:layout_marginBottom="42dp"
android:text="Lvl"
app:layout_constraintBottom_toTopOf="@+id/heroesListView"
app:layout_constraintEnd_toEndOf="@+id/textNickname"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/textNickname"
app:layout_constraintTop_toBottomOf="@+id/textNickname"
app:layout_constraintVertical_bias="0.562" />
</androidx.constraintlayout.widget.ConstraintLayout>
HeroesActivity
class HeroesActivity : AppCompatActivity() {
lateinit var heroesAdapt : HeroesAdapter
val listHero = ArrayList<TestHero>()
private val TAG = "HeroesActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_heroes)
getCurrentData()
val lisView : ListView = findViewById(R.id.heroesListView)
heroesAdapt = HeroesAdapter(this, listHero)
lisView.adapter = heroesAdapt
//heroesListView.adapter = heroesAdapt
// heroesAdapt = HeroesAdapter(this, arrayListOf("a","b","c","d","e","f"));
// lisView.adapter = heroesAdapt
}
private fun getCurrentData() {
val api = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(ApiRequest::class.java)
GlobalScope.launch(Dispatchers.IO) {
val response = api.herList().awaitResponse()
if (response.isSuccessful) {
val data = response.body()!!
Log.d(TAG, data.toString())
withContext(Dispatchers.Main){
// adapter.add(data.global.name)
// adapt.add(data.global.platform)
listHero.add(data)
heroesAdapt.notifyDataSetChanged()
textNickname.text = "${data.global.name} (${data.global.rank.rankDiv} divisions)"
textLvl.text = "Level: ${data.global.level.toString()}"
when(data.global.rank.rankName){
"Silver" -> textNickname.setTextColor(Color.parseColor("#7A7A79"))
"Gold" -> textNickname.setTextColor(Color.parseColor("#E6D600"))
"Platinum" -> textNickname.setTextColor(Color.parseColor("#36BBCE"))
}
}
}
}
}
}
I think the problem is in this piece of code
for((key) in category.legends.all){
Log.d("HeroesActivity", key)
heroText.text = key
}
And logs screen
TestHero.kt
data class TestHero (@SerializedName("global") val global: PlayerInf,
@SerializedName("legends")val legends: AllLegends)
data class PlayerInf (val name: String, val uid: Long, val avatar: String, val platform: String,
val level: Int, val toNextLevelPercent: Int, val internalUpdateCount: Int, val bans: BanInf, val rank: RankInf)
data class BanInf (val isActive: Boolean, val remainingSeconds: Int)
data class RankInf (val rankScore: Int, val rankName: String, val rankDiv: Int, val rankImg: String)
data class AllLegends (@SerializedName("all") val all: Map<String, LegendWrapper> = emptyMap())
data class LegendWrapper(
val data: List<PlayerPerformance>? = emptyList()
)
data class PlayerPerformance(val name: String, val value: Int, val key: String)
To the adapter, it's one item for one view. Your backing List has only one item. Your for loop inside getView()
is iterating some collection inside that single item, and setting the value of the same TextView over and over until it gets to the last one.
Since the backing type of your adapter is TestHero, your list view can only show one line item per instance of TestHero. You only have one instance of TestHero.
Based on what you're showing, you should make the backing type of your adapter whatever the type of the list TestHero.legends.all
is. In your coroutine, you can pull that list out of your TestHero and pass it to your Adapter. You'll need to make the backing list property mutable.
And like I said in the comments, don't use mutable lists for this. You should start with an empty list.
For example, if the type of this list is Legend, your adapter should look something like:
class HeroesAdapter(): BaseAdapter() {
var heroes: List<Legend> = emptyList()
override fun getCount(): Int = heroes.size
override fun getItem(position: Int): = heroes[position]
override fun getItemId(position: Int) = position
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val view = convertView ?: LayoutInflater.from(parent.context).inflate(R.layout.list_hero_view, parent, false)
val heroText: TextView = view.findViewById(R.id.textHeroView)
val hero = heroes[position]
heroText.text = hero.keys.first()
return view
}
}
And in your Activity, get rid of the listHero
property. In your coroutine, after you get your data, do
heroesAdapt.apply {
heroes = data.legends.all
notifyDataSetChanged()
}
Also, consider switching to RecyclerView. ListView is kind of obsolete and I keep expecting them to deprecate it because they have only worked on improving RecyclerView the past several years.