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é?
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!
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
}
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
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}
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)
}
}
}
}
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))
}
}
}
}
}