可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm trying to create a simple recyclerView in Kotlin with data that I get via Volley (which I have confirmed returns the correct data), I keep running to the error E/RecyclerView: No adapter attached; skipping layout
when in fact I have specified an adapter with the custom adapter class that I created:
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
}
}
This is my MainActivty class, where I make the actual call for the JSON and attempt to attach my adapter with my ArrayList that I have created:
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)
}
}
I have created a custom data class Image
which stores three fields: the imageUrl, submitter and color, all of which are derived from the JSON. I thought that calling notifyDataSetChanged()
on my adapter after the request was completed would allow the recyclerView to get updated and show the items, but nothing at all shows up on the screen. Does anyone have any idea as to where I messed up?
回答1:
You can download the source code from here(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)
}
}
}
Thanks!
回答2:
Look at following example, I think you this can give you an idea.
You can get the example from here : https://github.com/Siddharha/RecyclerviewTest_Kotlin
Main Activity
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)
}
}
Adapter Class
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
}
}
}
Item Class
internal class MyItem {
var name: String? = null
var number: String? = null
}
回答3:
try to use Delegate Adapters below is reference link.
Ref Link : https://android.jlelse.eu/keddit-part-4-recyclerview-delegate-adapters-data-classes-with-kotlin-9248f44327f7
回答4:
I have my RecyclerView Adapter which is as follows,
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))
}
}
}
}
}
回答5:
On .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()
}
Create a new .kt file for creating Adapter
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}
回答6:
I have created a nice adapter may be it helped in reducing 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)
}
}
}
}