web-dev-qa-db-fra.com

Essayer de créer un recyclerView simple dans Kotlin, mais l'adaptateur ne s'applique pas correctement

J'essaie de créer un recyclerView simple dans Kotlin avec les données que je reçois via Volley (ce qui, j’ai confirmé, renvoie les données correctes). Je continue à courir jusqu’à l’erreur E/RecyclerView: No adapter attached; skipping layout alors que j’ai spécifié un adaptateur avec la classe d’adaptateur personnalisé qui J'ai crée:

class ImageAdapter(var c: Context, var list: ArrayList<Image>) : RecyclerView.Adapter<ImageAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder? {
    val layoutInflater = LayoutInflater.from(parent.context)
    return ViewHolder(layoutInflater.inflate(R.layout.image_cardview, parent, false))
}

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    val imageUrl = list[position].url
    val submitter = list[position].submitter
    val color = list[position].color
    holder.submitterTV.text = submitter
    holder.card.setCardBackgroundColor(Color.parseColor(color))
}

override fun getItemCount() = list.size
class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){
    val card = itemView.card
    val submitterTV = itemView.submitter
    val imageView = itemView.image
}

}

Ceci est ma classe MainActivty, où je passe l'appel réel pour le JSON et tente de connecter mon adaptateur avec mon ArrayList que j'ai créé:

class MainActivity : AppCompatActivity() {
val images = ArrayList<Image>()
override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    imageList.layoutManager = LinearLayoutManager(applicationContext)
    request("https://api.unsplash.com/photos/curated/?client_id=API_KEY")
    imageList.adapter = ImageAdapter(applicationContext, images)

}

private fun request(url: String) {
    val queue = Volley.newRequestQueue(this)
    val stringRequest = JsonArrayRequest(url, Response.Listener<JSONArray> { response ->
        try {
            for (i in 0..(response.length() - 1)) {
                val image: Image = Image(response.getJSONObject(i).getJSONObject("urls").getString("full"), response.getJSONObject(i).getJSONObject("user").getString("username"), response.getJSONObject(i).getString("color"))
                images.add(image)
            }

            imageList.adapter.notifyDataSetChanged()

        } catch (e: JSONException) {
            e.printStackTrace()
        }
    }, Response.ErrorListener { })
    queue.add(stringRequest)
}
}

J'ai créé une classe de données personnalisée Image qui stocke trois champs: l'imageUrl, l'émetteur et la couleur, tous dérivés du JSON. Je pensais qu'appeler notifyDataSetChanged() sur mon adaptateur une fois la demande complétée permettrait à recyclerView d'être mis à jour et d'afficher les éléments, mais rien ne s'affiche du tout à l'écran. Est-ce que quelqu'un a une idée de l'endroit où je me suis trompé?

6
rakeshdas

Vous pouvez télécharger le code source ici ( Recyclerview In Kotlin Android )

MainActivity.kt:

package com.deepshikha.recyclerviewkotlin
import Android.app.Activity
import Android.os.Bundle
import Android.support.v7.widget.LinearLayoutManager
import Android.view.Window
import Android.view.WindowManager
import Android.widget.LinearLayout
import kotlinx.Android.synthetic.main.activity_main.*
import net.simplifiedcoding.recyclerviewexample.CustomAdapter

class MainActivity : Activity() {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        requestWindowFeature(Window.FEATURE_NO_TITLE)
        window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN)

        setContentView(R.layout.activity_main)

        val users = ArrayList<Model_Details>()
        users.add(Model_Details("Kaju katli", "Kaju katli, also known as kaju Katari or kaju barfi, is an Indian dessert similar to a barfi.",R.drawable.kaju))
        users.add(Model_Details("Doughnut", "The doughnut is popular in many countries and prepared in various forms as a sweet snack that can be homemade or purchased in bakeries, supermarkets, food stalls, and franchised specialty outlets",R.drawable.donuts))
        users.add(Model_Details("Panna cotta", "Panna cotta is an Italian dessert of sweetened cream thickened with gelatin and molded. The cream may be aromatized with rum, coffee, Vanilla, or other flavorings.",R.drawable.panna_cotta))
        users.add(Model_Details("Rose Cookies", "Rose cooky is a famous South Indian snack made during festivals",R.drawable.rosecookies))
        users.add(Model_Details("Belgian waffle", "In North America, Belgian waffles are a variety of waffle with a lighter batter, larger squares, and deeper pockets than ordinary American waffles",R.drawable.belgianwaffle))

        val obj_adapter = CustomAdapter(users)

        recyclerView.layoutManager = LinearLayoutManager(this, LinearLayout.VERTICAL, false)
        recyclerView.adapter = obj_adapter
    }


}

CustomAdapter.kt:

package net.simplifiedcoding.recyclerviewexample

import Android.support.v7.widget.RecyclerView
import Android.view.LayoutInflater
import Android.view.View
import Android.view.ViewGroup
import Android.widget.TextView
import com.deepshikha.recyclerviewkotlin.Model_Details
import com.deepshikha.recyclerviewkotlin.R
import kotlinx.Android.synthetic.main.adapter_details.view.*

class CustomAdapter(val userList: ArrayList<Model_Details>) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() {

    //this method is returning the view for each item in the list
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomAdapter.ViewHolder {
        val v = LayoutInflater.from(parent.context).inflate(R.layout.adapter_details, parent, false)
        return ViewHolder(v)
    }

    //this method is binding the data on the list
    override fun onBindViewHolder(holder: CustomAdapter.ViewHolder, position: Int) {
        holder.bindItems(userList[position])
    }

    //this method is giving the size of the list
    override fun getItemCount(): Int {
        return userList.size
    }

    //the class is hodling the list view
    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        fun bindItems(user: Model_Details) {
            itemView.tv_name.text=user.name
            itemView.tv_des.text=user.des
            itemView.iv_name.setImageResource(user.image)

        }
    }

}

Merci!

14
Deepshikha Puri

Regardez l'exemple suivant, je pense que cela peut vous donner une idée. 

Vous pouvez obtenir l'exemple à partir d'ici: https://github.com/Siddharha/RecyclerviewTest_Kotlin

Activité principale

class MainActivity : AppCompatActivity() {
private var myAdapter: MyAdapter? = null
private var arrayList: ArrayList<MyItem>? = null
private var layoutManager: RecyclerView.LayoutManager? = null
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    initialize()
    setupList()
    loaddata()
}

private fun loaddata() {

    for (i in 0..9) {
        val myItem = MyItem()
        myItem.name = "Sid_" + i
        myItem.number = "098899876" + i
        arrayList!!.add(myItem)
    }

    myAdapter!!.notifyDataSetChanged()

}

private fun setupList() {
    rlItems!!.layoutManager = layoutManager
    rlItems!!.adapter = myAdapter
}

private fun initialize() {
    arrayList = ArrayList<MyItem>()
    layoutManager = LinearLayoutManager(this, LinearLayout.VERTICAL, false)
    myAdapter = MyAdapter(arrayList!!, this, R.layout.item_cell)

  }
}

Classe d'adaptateur

internal class MyAdapter(private val arrayList: ArrayList<MyItem>,
                     private val context: Context,
                     private val layout: Int) : RecyclerView.Adapter<MyAdapter.ViewHolder>() {


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

override fun onBindViewHolder(holder: MyAdapter.ViewHolder, position: Int) {
    holder.bindItems(arrayList[position])
}

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

internal inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

    fun bindItems(items: MyItem) {
        itemView.tvName.text = items.name
        itemView.tvNumber.text = items.number
    }
  }
}

Classe d'objet

internal class MyItem {
var name: String? = null
var number: String? = null
}
4
Sid

essayez d'utiliser les adaptateurs de délégué ci-dessous est un lien de référence. 

Lien de référence: https://Android.jlelse.eu/keddit-part-4-recyclerview-delegate-adapters-data-classes-with-kotlin-9248f44327f7

1
Sanjay Bhalani

Sur .MainActivity.kt

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    //rcv is id of Recyclerview
    rcv.layoutManager = LinearLayoutManager(this)
    rcv.adapter = MyAdpater()
}

Créer un nouveau fichier .kt pour créer un adaptateur

class MyAdpater : RecyclerView.Adapter<ViewHolder>() {
val arr = listOf("A", "B", "C", "D", "E") //static array
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    holder.textView.setText(arr.get(position)) //set text to textview by position
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    return ViewHolder(TextView(parent.context))
 }

override fun getItemCount(): Int {
    return arr.count() //return array count
}}

class ViewHolder(val textView: TextView): RecyclerView.ViewHolder(textView){ //ViewHolder with textview}
0
iOS Lifee

J'ai créé un adaptateur Nice peut-être qu'il a aidé à réduire le code ..

class ResultActivity : BaseActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.question_list_activity)

        if (intent != null) {
            var results = intent.getParcelableArrayListExtra<Parcelable>("keyResults") as ArrayList<ResultBO>

            if (results.size > 0) {
                recycler_view.adapter = ResultAdapter(results, object : OnRecyclerItemClickListener {
                    override fun onItemClicked(view: View?, position: Int) {
                        /*var intent = Intent(this@SubjectListActivity,McqActivity::class.Java)
                        intent.putExtra("keyTagBO",subjects.get(position))
                        startActivity(intent)*/
                    }
                });
            }
        }

    }
}

item_result.xml

<?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:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:orientation="vertical">

    <TextView
        Android:id="@+id/titleTv"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:text="Dummy Value"
        Android:textAlignment="center"
        Android:textAppearance="@style/TextAppearance.AppCompat.Large" />

    <LinearLayout
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:layout_marginTop="10dp"
        Android:orientation="horizontal">

        <TextView
            Android:id="@+id/option1Tv"
            Android:layout_width="0dp"
            Android:layout_height="wrap_content"
            Android:layout_weight="1"
            Android:text="Dummy"
            Android:textAlignment="center"
            Android:textAppearance="@style/TextAppearance.AppCompat.Medium" />

        <TextView
            Android:id="@+id/option2Tv"
            Android:layout_width="0dp"
            Android:layout_height="wrap_content"
            Android:layout_weight="1"
            Android:text="Dummy Value"
            Android:textAlignment="center"
            Android:textAppearance="@style/TextAppearance.AppCompat.Medium" />

    </LinearLayout>


    <LinearLayout
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:layout_marginTop="10dp"
        Android:orientation="horizontal">

        <TextView
            Android:id="@+id/option3Tv"
            Android:layout_width="0dp"
            Android:layout_height="wrap_content"
            Android:layout_weight="1"
            Android:text="Dummy"
            Android:textAlignment="center"
            Android:textAppearance="@style/TextAppearance.AppCompat.Medium" />

        <TextView
            Android:id="@+id/option4Tv"
            Android:layout_width="0dp"
            Android:layout_height="wrap_content"
            Android:layout_weight="1"
            Android:text="Dummy Value"
            Android:textAlignment="center"
            Android:textAppearance="@style/TextAppearance.AppCompat.Medium" />

    </LinearLayout>


    <LinearLayout
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:orientation="horizontal">


    </LinearLayout>
</LinearLayout>

ResultADapter.class

class ResultAdapter(items: List<ResultBO>, onRecyclerItemClickListener: OnRecyclerItemClickListener) : BaseAdapter<ResultBO, ResultViewHolder>(items, onRecyclerItemClickListener) {

    override fun onCreateViewHolder(parent: ViewGroup, pos: Int): ResultViewHolder {
        return ResultViewHolder(parent, R.layout.item_result,onRecyclerItemClickListener)
    }
}

BaseViewHolder.class

abstract class BaseViewHolder<T : BaseModel>(parent: ViewGroup, @LayoutRes itemLayoutId: Int,
                                             var onRecyclerItemClickListener: OnRecyclerItemClickListener) :
        RecyclerView.ViewHolder(LayoutInflater.from(parent.context).inflate(itemLayoutId, parent,
                false)), View.OnClickListener {

    override fun onClick(v: View?) {
        onRecyclerItemClickListener.onItemClicked(v, adapterPosition)
    }

    abstract fun bindData(data: T)

    init {
        itemView.setOnClickListener(this)
    }
}

BaseAdapter

abstract class BaseAdapter<T : BaseModel, U : BaseViewHolder<T>>
(var items: List<T>, var onRecyclerItemClickListener: OnRecyclerItemClickListener)
    : RecyclerView.Adapter<U>() {

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

    override fun onBindViewHolder(holder: U, pos: Int) {
        holder.bindData(items.get(pos))
    }
}

ResultViewHolder.class

class ResultViewHolder(parent: ViewGroup, itemLayoutId: Int, onRecyclerItemClickListener: OnRecyclerItemClickListener) : BaseViewHolder<ResultBO>(parent, itemLayoutId, onRecyclerItemClickListener) {

    override fun bindData(data: ResultBO) {
        itemView.titleTv.setText(data.questionBO.title)

        itemView.option1Tv.setText(data.questionBO.options.get(0))
        itemView.option2Tv.setText(data.questionBO.options.get(1))
        itemView.option3Tv.setText(data.questionBO.options.get(2))
        itemView.option4Tv.setText(data.questionBO.options.get(3))

        when(data.orignalAnswer()) {
            OptionType.A -> itemView.option1Tv.setBackgroundColor(Color.GREEN)
            OptionType.B -> itemView.option2Tv.setBackgroundColor(Color.GREEN)
            OptionType.C -> itemView.option3Tv.setBackgroundColor(Color.GREEN)
            OptionType.D -> itemView.option4Tv.setBackgroundColor(Color.GREEN)
        }

        if(!data.isCorrectlyAnswered()){
            when(data.selectedOption) {
                OptionType.A -> itemView.option1Tv.setBackgroundColor(Color.RED)
                OptionType.B -> itemView.option2Tv.setBackgroundColor(Color.RED)
                OptionType.C -> itemView.option3Tv.setBackgroundColor(Color.RED)
                OptionType.D -> itemView.option4Tv.setBackgroundColor(Color.RED)
            }
        }

    }
}
0
Xar E Ahmer

J'ai mon adaptateur RecyclerView qui est comme suit, 

internal class OptionsAdapter : RecyclerView.Adapter<OptionsAdapter.ViewHolder>() {

private val mOptionList = ArrayList<Option>()
private var mOnItemClickListener: OnItemClickListener<Option>? = null

var data: List<Option>
    get() = mOptionList
    set(list) {
        mOptionList.clear()
        mOptionList.addAll(list)
        notifyDataSetChanged()
    }

fun setOnItemClickListener(listener: OnItemClickListener<Option>) {
    mOnItemClickListener = listener
}

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

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    val option = getItem(position)
    holder.textViewOption.setText(option.text)
    holder.textViewDescription.setText(option.subText)
}



private fun getItem(index: Int): Option {
    return mOptionList[index]
}

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


internal inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    var textViewOption: TextView
    var textViewDescription: TextView
    var imageViewOptionIcon: ImageView

    init {
        textViewOption = itemView.findViewById<TextView>(R.id.textview_option)
        imageViewOptionIcon = itemView.findViewById<ImageView>(R.id.imageview_option_icon)
        textViewDescription = itemView.findViewById<TextView>(R.id.textview_description)
        itemView.setOnClickListener {
            if (mOnItemClickListener != null) {
                mOnItemClickListener!!.onItemClick(getItem(adapterPosition))
            }
        }
    }
  }
}
0
Saurabh Padwekar