I have a simple new application with a recycler view that should display "songs" but at the moment it displays non. Non of the functions on the adapter are being called, not even getItemCount.
What ive tried:
I am not new to android, ive been developing on android xamarin, xamarin maui and now moved to android studio. I cant seem to find anything wrong with my code. Can anyone help? Thank you.
SongAdapter:
/**
* Song adapter
*
* @property songs a given list of songs
* @constructor Create empty Song adapter
*/
class SongAdapter(private val songs: MutableList<Song> = mutableListOf()) : RecyclerView.Adapter<SongAdapter.SongVH>() {
/**
* Song view holder
*
* @property songDisplayView the song display view being held
* @constructor Create empty Song view holder
*/
class SongVH(val songDisplayView: SongDisplayView) : ViewHolder(songDisplayView){
}
override fun getItemCount(): Int {
return songs.count()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SongVH {
return SongVH(SongDisplayView(parent.context,null,songs[viewType]))
}
override fun onBindViewHolder(holder: SongVH, position: Int) {
holder.songDisplayView.setSong(songs[position])
}
/**
* Update songs to the given new songs
*
* @param newSongs given new songs
*/
fun updateSongs(newSongs: Iterable<Song>){
songs.clear()
songs.addAll(newSongs)
notifyItemRangeChanged(0,songs.size)
}
/**
* Adds a new song to the song list
*
* @param newSong a given new song
*/
fun addSong(newSong : Song){
songs.add(newSong)
notifyItemInserted(songs.size-1)
}
/**
* Removes a song from the song list
*
* @param index a given index to remove from
*/
fun removeSong(index: Int){
songs.removeAt(index)
notifyItemRemoved(index)
}
/**
* Updates the song at the given index to a new song
*
* @param song the new song
* @param index a given index
*/
fun updateSong(song: Song, index: Int){
songs[index] = song
notifyItemChanged(index)
}
}
SongDisplayView:
class SongDisplayView(context: Context,attributeSet: AttributeSet?,song: Song = Song()) : LinearLayout(context,attributeSet) {
private val titleView: TextView = TextView(context)
init {
titleView.text = song.name
titleView.textSize = 18f
addView(titleView)
}
fun setSong(song: Song ) {
titleView.text = song.name
}
}
MainActivity:
class MainActivity : AppCompatActivity() {
private lateinit var binding : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
binding = ActivityMainBinding.inflate(layoutInflater)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
val songAdapter = SongAdapter(mutableListOf(Song("Song 1"),Song("Song 2"), Song("Song 3")))
binding.songsRecycler.adapter = songAdapter
songAdapter.notifyDataSetChanged()
}
}
activity_main layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:orientation="vertical"
tools:context=".MainActivity" >
<TextView
android:text="hello world"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<androidx.recyclerview.widget.RecyclerView
android:background="#fadada"
android:id="@+id/songsRecycler"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
You're able to see the background color of the recycler because you initially set the layout using setContentView(R.layout.activity_main)
.
But you inflated the same activity_main
layout again using viewBinding. Then you setup the recycler (binding.songsRecycler
) from this newly inflated layout.
The newly inflated layout remains invisible until you set it as the content view using setContentView(binding.root)
. That's why recycler items aren't displayed.
Just set binding.root
in setContentView
.
class MainActivity : AppCompatActivity() {
private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(binding.root)
// other codes ...
}
}