Search code examples
androidandroid-fragmentskotlinandroid-recyclerviewadapter

My Adapter seems to be receiving data, but it's not being displayed in my RecyclerView. Any ideas as to what I am doing wrong?


So, I've been debugging for a while, and I can't seem to find where my error is. On my Debug console it shows the size of item list I am receiving from the response, with the data associated with each item in the list. It also shows the id of the textviews I set on the Adapter, but when I load the app I only get the Toast message I set on my fragment to verify I am receiving data, but no data on my textviews

ListFragment

class ListFragment : Fragment() {

    private val spaceVM : MainViewModel by viewModels()
    private lateinit var spaceAdapter: SpaceAdapter

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_list, container, false)
    }

    override fun onResume() {
        super.onResume()
        setUpObserver()
    }

    private fun setUpObserver(){
        spaceVM.spaceLiveData.observe(this, Observer {
            val data = spaceVM.spaceLiveData.value
            if (data != null) {
                Toast.makeText(context, data.toString(), Toast.LENGTH_LONG).show()
                //ID of my recycler view using Kotlin Android Extensions
                rvSpace.apply {
                    layoutManager = LinearLayoutManager(activity)
                    spaceAdapter = SpaceAdapter()
                    spaceAdapter.submitSpaceList(data)
                    adapter = spaceAdapter
                }

            }

        })
    }
}

SpaceAdapter

class SpaceAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    private var items : List<SpaceXResponse> = ArrayList()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return SpaceViewHolder(
            LayoutInflater.from(parent.context).inflate(R.layout.card, parent, false)
        )
    }
    override fun getItemCount(): Int {
        return items.size
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        when(holder){
            is SpaceViewHolder ->{
                holder.bind(items.get(position))
            }
        }
    }


    fun submitSpaceList(spaceList : List<SpaceXResponse>){
        items = spaceList
    }

    class SpaceViewHolder constructor(itemView: View) : RecyclerView.ViewHolder(itemView){
        val missionName : TextView = itemView.tvMissionName
        val rocketName : TextView = itemView.tvRocketName
        val launchSite : TextView = itemView.tvLaunchSite
        val dol : TextView = itemView.tvDOL

        fun bind(spacePost : SpaceXResponse){
            missionName.setText(spacePost.missionName)
            rocketName.setText(spacePost.rocket?.rocketName)
            launchSite.setText(spacePost.launchSite?.siteName)
            dol.setText(spacePost.launchDateLocal)
        }
    }
}

Maybe it could be the way I set my holder on onBindViewHolder? I put a debug breakpoint on it and i get: "ViewHolder{e0b3537 position =0 id=-1, oldPos=-1, pLpos:-1 no parent}" But I feel like I added the parent already on onCreateViewHolder

Here is my Fragment xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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=".view.ListFragment">
<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toTopOf="@+id/card"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rvSpace"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </ScrollView>

</androidx.constraintlayout.widget.ConstraintLayout>

</FrameLayout>

And here is my Card xml I am trying to inflate into my RecyclerView

<?xml version="1.0" encoding="utf-8"?>
    <com.google.android.material.card.MaterialCardView
xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_margin="10dp"
        android:gravity="center"
        app:layout_constraintBottom_toTopOf="@+id/card"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="305dp">

            <TextView
                android:id="@+id/tvMissionName"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                app:layout_constraintBottom_toTopOf="@+id/tvRocketName"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintHorizontal_bias="0.0"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <TextView
                android:id="@+id/tvRocketName"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                app:layout_constraintBottom_toTopOf="@id/tvLaunchSite"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/tvMissionName" />

            <TextView
                android:id="@+id/tvLaunchSite"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:text="@{space.launchSite.siteName}"
                app:layout_constraintBottom_toTopOf="@id/tvDOL"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/tvRocketName" />

            <TextView
                android:id="@+id/tvDOL"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                app:layout_constraintBottom_toTopOf="@+id/ivImage"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/tvLaunchSite" />

            <ImageView
                android:id="@+id/ivImage"
                android:layout_width="350px"
                android:layout_height="350px"
                android:src="@drawable/ic_launcher_background"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent" />
        </androidx.constraintlayout.widget.ConstraintLayout>
    </com.google.android.material.card.MaterialCardView>

Solution

  • I think, you lost notifyDatasetChanged call on your adapter.

    Also xml of viewholder looks bit suspicious, it's height is 0 and it uses height constrain on nonexistent id app:layout_constraintBottom_toTopOf="@+id/card". After all, you can narrow error place, you can set log in on bindviewholder, to get if data is set. If adapter binds holder proper number of times - then problem is in viewholder code