Home > Software engineering >  E/RecyclerView: No adapter attached; skipping layout in fragment android studio using kotlin
E/RecyclerView: No adapter attached; skipping layout in fragment android studio using kotlin

Time:08-09

i am a beginner in android studio with kotlin i alwayes struggle in fragment, they are difficult to cope with. i am trying to implement recyclerview in fragment but it does not work i keep getting this error E/RecyclerView: No adapter attached; skipping layout here is my fragment

package com.example.pgm

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView

// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"

/**
 * A simple [Fragment] subclass.
 * Use the [VSFragment.newInstance] factory method to
 * create an instance of this fragment.
 */
class VSFragment : Fragment() {

    // TODO: Rename and change types of parameters
    private var param1: String? = null
    private var param2: String? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {
            param1 = it.getString(ARG_PARAM1)
            param2 = it.getString(ARG_PARAM2)
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        val rv   = view?.findViewById<RecyclerView>(R.id.activeSubsRecycler)

       val subscription = ArrayList<SubscriptionData>()
        subscription.add(SubscriptionData("ghassan","1000","2002/1/1","2002/1/3"))
        subscription.add(SubscriptionData("ameer","2000","2002/1/1","2002/1/3"))
        subscription.add(SubscriptionData("ahmad","9893", "2002/1/1","2002/1/3"))
        subscription.add(SubscriptionData("saif","42452", "2002/1/1","2002/1/3"))
        subscription.add(SubscriptionData("ghassan","453", "2002/1/1","2002/1/3"))
        subscription.add(SubscriptionData("ameer","3354", "2002/1/1","2002/1/3"))
        subscription.add(SubscriptionData("ghassan","1000","2002/1/1","2002/1/3"))
        subscription.add(SubscriptionData("ameer","2000","2002/1/1","2002/1/3"))
        subscription.add(SubscriptionData("ahmad","9893", "2002/1/1","2002/1/3"))
        subscription.add(SubscriptionData("saif","42452", "2002/1/1","2002/1/3"))
        subscription.add(SubscriptionData("ghassan","453", "2002/1/1","2002/1/3"))
        subscription.add(SubscriptionData("ameer","3354", "2002/1/1","2002/1/3"))



        rv?.setHasFixedSize(true);
        if (rv != null) {
            rv.layoutManager = LinearLayoutManager(activity, RecyclerView.VERTICAL, false)
        }
        if (rv != null) {
            rv.adapter = activity?.let { SubscriptionAdapter(it,subscription) }
        }

        return inflater.inflate(R.layout.fragment_v_s, container, false)


    }

    companion object {
        /**
         * Use this factory method to create a new instance of
         * this fragment using the provided parameters.
         *
         * @param param1 Parameter 1.
         * @param param2 Parameter 2.
         * @return A new instance of fragment VSFragment.
         */
        // TODO: Rename and change types and number of parameters
        @JvmStatic
        fun newInstance(param1: String, param2: String) =
            VSFragment().apply {
                arguments = Bundle().apply {
                    putString(ARG_PARAM1, param1)
                    putString(ARG_PARAM2, param2)
                }
            }
    }
}

my adapter


package com.example.pgm

import android.content.Context
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.AnimationUtils
import android.widget.TextView
import androidx.cardview.widget.CardView
import androidx.recyclerview.widget.RecyclerView


class SubscriptionAdapter (private val context: Context, private val subscriptions : ArrayList<SubscriptionData>):
    RecyclerView.Adapter<SubscriptionAdapter.ViewHolder>() {
    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var my_name = itemView.findViewById<TextView>(R.id.tx_name) as TextView
        var my_value = itemView.findViewById<TextView>(R.id.tx_value) as TextView
        var card_View = itemView.findViewById<CardView>(R.id.cardViewooo) as CardView
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val v = LayoutInflater.from(parent.context).inflate(R.layout.design2,parent, false)
        return ViewHolder(v)
    }



    override fun getItemCount(): Int {
        return subscriptions.size
    }


    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val data = subscriptions[position]
        holder.my_name.text = data.name
        holder.my_value.text = data.value
        holder.card_View.startAnimation(AnimationUtils.loadAnimation(holder.itemView.context,R.anim.main_anim))
        holder.itemView.setOnClickListener {
            val i = Intent(context,Subscription::class.java)
            i.putExtra("name",subscriptions[position].name)
            i.putExtra("value",subscriptions[position].value)
            i.putExtra("startDate",subscriptions[position].startDate)
            i.putExtra("endDate",subscriptions[position].endDate)
            context.startActivity(i)

        }    }
}

XML

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".VSFragment">

    <androidx.recyclerview.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@ id/activeSubsRecycler"

        />

</FrameLayout>

what should i do?

CodePudding user response:

onCreateView is where you're meant to inflate a layout for your Fragment to display, and then return it. You're doing that at the end:

return inflater.inflate(R.layout.fragment_v_s, container, false)

But until you do that, the Fragment doesn't have a view! When you try to access view at the start, you're actually calling getView():

Get the root view for the fragment's layout (the one returned by onCreateView), if provided.

So when you do this at the start of onCreateView:

val rv   = view?.findViewById<RecyclerView>(R.id.activeSubsRecycler)

there is no view, so rv is null. So all the setup you're trying to do doesn't happen, because you're null-checking rv before you do them, and since it's null, nothing happens.


When you want to do setup in onCreateView, you need to inflate your view first, then do all your setup on it, and then return that view:

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    // get your view inflated
    val view = inflater.inflate(R.layout.fragment_v_s, container, false)

    // you can make a list like this, if you make your adapter take a
    // List<SubscriptionData> instead of an ArrayList<SubscriptionData> (which you should)
    val subscription = listOf(
        SubscriptionData("ghassan","1000","2002/1/1","2002/1/3"),
        SubscriptionData("ameer","2000","2002/1/1","2002/1/3"),
        ...
    )

    // Poke around at the stuff in it to get it set up

    // This is just a way to null-check once - if it's found (not null),
    // this 'let' block will run with the RecyclerView as a variable called 'rv'
    view.findViewById<RecyclerView>(R.id.activeSubsRecycler)?.let { rv ->
        // don't use an Activity as a context here - just use requireContext,
        // you'll have access to one at this point
        rv.layoutManager = LinearLayoutManager(requireContext(), RecyclerView.VERTICAL, false)
        rv.adapter = SubscriptionAdapter(requireContext(),subscription)
    }

    // now return the inflated view, which you've set up!
    return view
}

Get the idea? You inflate a layout that you're going to pass back, but if you need to set up anything on it, you do that before you return it. (You can be smarter in there, using run or better yet apply, but if you don't know how that would be more elegant don't worry about it!)

The other option is to override onViewCreated to handle your setup stuff - so inflate a view in onCreateView, and that'll get passed into onViewCreated where you can work with it, do setup etc. Whichever you prefer!

  • Related