Nested vertical recyclerviews scroll lag - android

My use case model looks like:
data class CombinedModel(
val header: String?,
val contactsList: List<ContactModel>
)
I have to display this model as List < CombinedModel > in a recyclerview so it will be a header title with a list of items below it. My Xml layout for the parent recyclerview is simply a MaterialTextView and a RecyclerView. The child recyclerview contains the layout for the list of ContactModel.
The problem is when scrolling down the parent list, each time a child RecyclerView comes onto screen there is a noticeable stutter/lag as it draws the next ContactModel list. The goal here would be to get this working with a smooth buttery scroll and no lag.
class ParentAdapter
constructor(
private val interaction: ContactAdapter.Interaction? = null,
private var customisedColour: String?
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(),
Filterable {
private val viewPool = RecyclerView.RecycledViewPool()
private var list = emptyList<DirectoryCombinedModel>()
private var listAll = directoryList
private val listFilter = ListFilter()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return ParentViewHolder(
RvParentBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
),
interaction = interaction
)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is ParentViewHolder -> {
list[position].let { holder.bind(it) }
}
}
}
override fun getItemCount(): Int {
return if (!list.isNullOrEmpty()) {
list.size
} else 0
}
fun updateList(updatedList: List<CombinedModel>) {
list = updatedList
listAll = updatedList
notifyDataSetChanged()
}
inner classParentViewHolder
constructor(
private val binding: RvParentBinding,
private val interaction: ContactAdapter.Interaction?
) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: CombinedModel) = with(itemView) {
with(binding) {
headerTitle.text = item.header
val childLayoutManager = GridLayoutManager(
rv.context, 2
)
childLayoutManager.initialPrefetchItemCount = item.contactList.size
rv.apply {
layoutManager = childLayoutManager
adapter = ContactAdapter(
interaction = interaction,
customisedColour = customisedColour,
contacts = item.contactsList
)
setHasFixedSize(true)
setRecycledViewPool(viewPool)
}
}
}
}
PARENT XML
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:id="#+id/mainContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.card.MaterialCardView
android:id="#+id/cvHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardBackgroundColor="#color/transparent"
app:cardCornerRadius="0dp"
app:cardElevation="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textview.MaterialTextView
android:id="#+id/headerTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="start"
android:paddingStart="#dimen/_8sdp"
android:paddingTop="#dimen/_18sdp"
android:paddingEnd="#dimen/_8sdp"
android:paddingBottom="#dimen/_12sdp"
android:text="#string/title"
android:textColor="#color/textColorPrimary"
android:textSize="#dimen/text_size_subHeading"
android:textStyle="bold" />
</com.google.android.material.card.MaterialCardView>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nestedScrollingEnabled="false"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/cvHeader"
app:spanCount="2"
tools:listitem="#layout/rv_contact" />
</androidx.constraintlayout.widget.ConstraintLayout>
CHILD ADAPTER
class DirectoryContactAdapter
constructor(
private val interaction: Interaction? = null,
private val customisedColour: String?,
private var contacts: List<ContactModel>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var contactsAll = contacts
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return ContactViewHolder(
RvContactBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
),
interaction = interaction
)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is ContactViewHolder -> {
contacts[position].let { holder.bind(it) }
}
}
}
override fun getItemCount(): Int {
return if (!contacts.isNullOrEmpty()) {
contacts.size
} else 0
}
inner class ContactViewHolder
constructor(
private val binding: RvContactBinding,
private val interaction: Interaction?
) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: ContactModel) = with(itemView) {
with(binding) {
setOnClickListener {
interaction?.onItemSelected(absoluteAdapterPosition, item)
}
name.text = item.name
role.text = item.title
Glide.with(contactImage.context)
.load(item.imageName)
.centerCrop()
.circleCrop()
.placeholder(R.drawable.ic_contact)
.error(R.drawable.ic_contact)
.transition(
DrawableTransitionOptions.withCrossFade()
).into(contactImage)
directoryImageBackground.setTintHex(customisedColour)
}
}
}

Solved it by following the approach layed out in this accepted answer: Divide elements on groups in RecyclerView or Grouping Recyclerview items ,say by date

Related

room android title is not filled in the list on StartFragment

I get the table and complete the title in the list on the start page, but the text not updated for some reason, what could be the problem?
I have a table:
#Entity(tableName = "Note_table")
class NoteModel (
#PrimaryKey(autoGenerate = true)
var id: Int = 0,
#ColumnInfo
var title: String = "",
#ColumnInfo
var description: String = ""
) : Serializable
I have RecyclerView:
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:cardElevation="5dp"
app:cardCornerRadius="3dp"
android:layout_margin="1dp">
<TextView
android:id="#+id/item_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:text="title"
android:textColor="#color/blue"
android:textSize="20sp"
android:textStyle="bold" />
</androidx.cardview.widget.CardView>
and in the class NoteAdapte, i complete in the title (here - binding.itemTitle.text = listNote[position].title), but in the activity I get itemTitle.text = title:
class NoteAdapter: RecyclerView.Adapter<NoteAdapter.NoteViewHolder>() {
lateinit var binding: ItemLayoutBinding
var listNote = emptyList<NoteModel>()
class NoteViewHolder(view: View): RecyclerView.ViewHolder(view) {
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteViewHolder {
binding = ItemLayoutBinding.inflate(LayoutInflater.from(parent.context), parent, false)
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_layout, parent, false)
return NoteViewHolder(view)
}
override fun onBindViewHolder(holder: NoteViewHolder, position: Int) {
binding.itemTitle.text = listNote[position].title
}
override fun getItemCount(): Int {
return listNote.size
}
#SuppressLint("NotifyDataSetChanged")
fun setList(list: List<NoteModel>){
listNote = list
notifyDataSetChanged()
}
override fun onViewAttachedToWindow(holder: NoteViewHolder) {
super.onViewAttachedToWindow(holder)
holder.itemView.setOnClickListener{
StartFragment.clickNote(listNote[holder.adapterPosition])
}
}
override fun onViewDetachedFromWindow(holder: NoteViewHolder) {
holder.itemView.setOnClickListener(null)
}
}
link to Git: https://github.com/Avdors/RoomLesson.git
enter image description here
You are suppose to have a ItemLayoutBinding per item in your Adapter.
Here you are not.
First change the declaration of the NoteViewHolder class.
class NoteViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val binding: ItemLayoutBinding
init {
binding = ItemLayoutBinding.bind(view)
}
}
The onCreateViewHolder method become :
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_layout, parent, false)
return NoteViewHolder(view)
}
And the onBindViewHolder become:
override fun onBindViewHolder(holder: NoteViewHolder, position: Int) {
holder.binding.itemTitle.text = listNote[position].title
}

Can't show items by sections correctly in recyclerview in kotlin

I am relatively new in kotlin and I would like to know how I can display items by sections, like this: showing data in sections . I have two services, one returns the list of section names and the other returns the items for each section.
So far I did the following, the view is like this:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools">
<TextView
android:id="#+id/header_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="header" />
<androidx.appcompat.widget.SwitchCompat
android:id="#+id/header_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/list_productos_seccion"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="#+id/header_switch"
app:layout_constraintStart_toStartOf="#+id/header_title"
app:layout_constraintTop_toBottomOf="#+id/header_title" />
</androidx.constraintlayout.widget.ConstraintLayout>
and in my outer adapter I did the following, where I pass a list of sections to the adapter and for each one I consult the service to obtain items and display it:
class SeccionesAdapter(
var seccionClickAdapter: SeccionClickAdapter,
private val context: Context,
var fragment: Fragment,
var productoViewModel: ProductoViewModel,
var vm: ClientActivityViewModel
): RecyclerView.Adapter<SeccionesAdapter.MyViewHolder>() {
interface SeccionClickAdapter{
fun onSeccionClick(producto: ProductoQryDTO)
}
var dataList = emptyList<SeccionQryDTO>()
var productosLista = ArrayList<ProductoQryDTO>()
inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun setData(seccionDTO: SeccionQryDTO) {
itemView.header_title.text = seccionDTO.nombre
itemView.header_switch.isChecked = seccionDTO.isSelected?: true
itemView.list_productos_seccion.layoutManager = LinearLayoutManager(context)
if (itemView.header_switch.isChecked) {
itemView.list_productos_seccion.visibility = View.VISIBLE
dataFromServer(seccionDTO.id, itemView)
}
itemView.header_switch.setOnCheckedChangeListener { _, isChecked -> visible(isChecked, seccionDTO.id) }
}
fun visible(isChecked: Boolean, idSeccionDTO: Int) {
if (isChecked) {
itemView.list_productos_seccion.visibility = View.VISIBLE
dataFromServer(idSeccionDTO, itemView)
} else {
itemView.list_productos_seccion.visibility = View.GONE
}
}
}
fun dataFromServer(idSeccionDTO: Int, itemView: View) {
productosLista.clear()
productoViewModel.getItems(
idSeccionDTO,
{
fragment.activity?.runOnUiThread {
productosLista.clear()
productosLista.addAll(it.data!!)
itemView.list_productos_seccion.adapter = ProductoxSeccionAdapter(context, productosLista, seccionClickAdapter)
}
}, {
Log.e("Error", "", it)
}
)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(LayoutInflater.from(context).inflate(R.layout.item_header_model, parent, false))
}
override fun getItemCount(): Int {
return dataList.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.setData(dataList[position]!!)
}
fun setSecciones(seccionesList : List<SeccionQryDTO>) {
this.dataList = seccionesList
notifyDataSetChanged()
}
}
The problem is that when the application is loaded, sometimes the amount of items that should be for each section is not shown, and when I scroll it begins to make calls to the service, also the elements disappear and it remains blank as shown in this image
blank space in sections.
Could you help me please? I don't know how I could handle this situation or if I should implement it in some other way
EDIT
This is my inner adapter: ProductoxSeccionAdapter
class ProductoxSeccionAdapter (
private val context: Context,
var listProductos: List<ProductoQryDTO>?,
var seccionClickAdapter: SeccionesAdapter.SeccionClickAdapter
) : RecyclerView.Adapter<ProductoxSeccionAdapter.MyViewHolder>() {
inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun setData(producto: ProductoQryDTO) {
itemView.nombreProductoLista.text = producto.nombre
itemView.descProductoLista.text = producto.detalle
itemView.precioProductoLista.text = producto.simboloMoneda + producto.precio
itemView.setOnClickListener { seccionClickAdapter.onSeccionClick(producto) }
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(LayoutInflater.from(context).inflate(R.layout.item_producto_cliente_lista, parent, false))
}
override fun getItemCount(): Int {
return listProductos!!.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.setData(listProductos!![position])
}
}

RecyclerView doesn't display last item when multiple ViewHolders are used

I'm using androidx.recyclerview.widget.RecyclerView to display a list of items, separated by an other item as a "header" with some aggregated values.
When i put only one item in my list without adding the header, everything is ok and the item is displayed correctly. As soon as i add the header item, only the header is displayed and the one single item isn't shown.
When i add two items and the header, the header and one item are displayed. I don't know why the last item of my list is missing altough it exists in the adapters datasource.
My ListAdapter inherits from RecyclerView.Adapter<RecyclerView.ViewHolder> and uses two ViewHolders detected by a viewType property of my list items.
When loading the data, the onBindViewHolder method isn't called for the last item in my list, even tough the item is in the visible section of my screen.
Does anybody has a hint, why this happens?
class ListAdapter(val onClick: (position: Long) -> Unit,
val onLongClick: (Long) -> Unit,
val onShareClick: (id: Long?) -> Unit) : RecyclerView.Adapter<RecyclerView.ViewHolder>(),
BindableAdapter<List<ListAdapterItem<*>>> {
var items: List<ListAdapterItem<*>> = emptyList()
private var actionMode: ActionMode? = null
var tracker: SelectionTracker<Long>? = null
init {
setHasStableIds(true)
}
override fun setData(data: List<ListAdapterItem<*>>) {
this.items = data // all items are set correctly here!!
notifyDataSetChanged()
}
override fun getItemViewType(position: Int): Int {
return if (items.isEmpty()) EMPTY else items[position].viewType
}
override fun getItemCount(): Int {
return if (items.isEmpty()) 1 else items.filter { it.viewType == ITEM }.size
}
override fun getItemId(position: Int): Long = position.toLong()
fun getItem(position: Long): ListViewModel.ListItem = item[position.toInt()].value as ListViewModel.ListItem
fun setActionMode(actionMode: ActionMode?) {
this.actionMode = actionMode
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
EMPTY -> EmptyViewHolder(parent)
HEADER -> HistoryGroupHeaderViewHolder(parent)
else -> HistoryViewHolder(parent)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is HistoryViewHolder) {
val item = items[position].value as ListViewModel.ListItem
tracker?.let {
holder.bind(item, it.isSelected(position.toLong()))
}
holder.itemView.setOnClickListener {
onClick(position.toLong())
}
holder.itemView.findViewById<AppCompatImageView>(R.id.history_item_share)?.setOnClickListener {
onShareClick(item.id)
}
}
else if (holder is HistoryGroupHeaderViewHolder) {
val header = items[position].value as ListViewModel.ListSectionHeader
holder.bind(header)
}
}
class HistoryViewHolder(
private val parent: ViewGroup,
private val binding: at.app.databinding.ViewHistoryListItemBinding = DataBindingUtil.inflate(
LayoutInflater.from(parent.context),
R.layout.view_history_list_item,
parent,
false
)
) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: ListViewModel.ListItem, isActivated: Boolean = false) {
binding.model = item
itemView.isActivated = isActivated
val imageView = itemView.findViewById<AppCompatImageView>(R.id.history_item_image)
if(itemView.isActivated) {
val parameter = imageView?.layoutParams as ConstraintLayout.LayoutParams
parameter.setMargins(
parent.context.resources.getDimension(R.dimen.spacing_small).toInt(),
parent.context.resources.getDimension(R.dimen.spacing_small).toInt(),
parent.context.resources.getDimension(R.dimen.spacing_small).toInt(),
parent.context.resources.getDimension(R.dimen.spacing_small).toInt()
)
imageView.layoutParams = parameter
} else {
val parameter = imageView?.layoutParams as ConstraintLayout.LayoutParams
parameter.setMargins(0,0,0,0)
imageView.layoutParams = parameter
}
}
fun getItemDetails(): ItemDetailsLookup.ItemDetails<Long> =
object : ItemDetailsLookup.ItemDetails<Long>() {
override fun getPosition(): Int = adapterPosition
override fun getSelectionKey(): Long? = itemId
}
}
class HistoryGroupHeaderViewHolder(
private val parent: ViewGroup,
private val binding: at.app.databinding.ViewHistoryListGroupHeaderItemBinding = DataBindingUtil.inflate(
LayoutInflater.from(parent.context),
R.layout.view_history_list_group_header_item,
parent,
false
)
) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: ListViewModel.ListSectionHeader) {
binding.model = item
}
}
class EmptyViewHolder(
private val parent: ViewGroup, view: View = LayoutInflater.from(parent.context).inflate(
R.layout.view_history_empty_item,
parent,
false
)
) : RecyclerView.ViewHolder(view)
companion object {
const val EMPTY = 0
const val ITEM = 1
const val HEADER = 2
}
}
class MyItemDetailsLookup(private val recyclerView: RecyclerView) : ItemDetailsLookup<Long>() {
private val log = LoggerFactory.getLogger(ListAdapter::class.java)
override fun getItemDetails(e: MotionEvent): ItemDetails<Long>? {
val view = recyclerView.findChildViewUnder(e.x, e.y)
if (view != null) {
return try {
if(recyclerView.getChildViewHolder(view) is ListAdapter.HistoryViewHolder) {
(recyclerView.getChildViewHolder(view) as ListAdapter.HistoryViewHolder)
.getItemDetails()
} else {
null
}
} catch (ex: Exception) {
log.error("Error on getItemDetails. ", ex)
null
}
}
return null
}
}
data class ListAdapterItem<out T>(val value: T, val viewType: Int)
And this is my layout:
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
<import type="android.view.View" />
<variable
name="viewModel"
type="at.app.ui.viewmodel.ListViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="#+id/list_app_bar"
layout="#layout/layout_toolbar" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/history_recycler_view"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#android:color/transparent"
android:scrollbars="vertical"
app:data="#{viewModel.items}"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/list_app_bar" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
When i add two items and the header, the header and one item are
displayed.
problem is in your getItemCount method.
override fun getItemCount(): Int {
return if (items.isEmpty()) 1 else items.filter { it.viewType == ITEM }.size
}
If you want to show 1 header and 2 elements that means that there are must be 3 items in recyclerview, so getItemCount must return 3. But now it looks like getItemCount will return 2, thats why recycerlview doesn't even create third element.

ImageView doesn't load images in the RecyclerView after binding the Url

I am a newbie with android databinding, but the ImageView doesn't bind in the RecyclerView. I have read several blogs but no luck. What am I missing?
Below are some of the blog posts I have read:
link 1
link2
Below is how I have styled my xml layout.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="movie"
type="com.movieapp.huxymovies.model.Result" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:background="#color/bg"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="0dp"
android:layout_marginTop="8dp"
android:background="#color/bg"
android:orientation="horizontal">
<ImageView
android:id="#+id/img"
android:layout_width="70dp"
android:layout_height="100dp"
android:layout_marginLeft="8dp"
app:movieImage="#{movie.MPosterPath}" />
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
</layout>
Then this is the modal class which contains all the attributes:
#Entity(tableName = "Results")
class Result {
companion object {
#JvmStatic
#BindingAdapter("movieImage")
fun LoadImage(view: View, mPosterPath: String?) {
val imageView = view as ImageView
Glide.with(view.context)
.load(Utils.IMAGE_BASE_URL + mPosterPath)
.into(imageView)
}
#BindingAdapter("rating")
fun setRating(ratingBar: RatingBar, rating: Float) {
if (rating != null) {
ratingBar.rating = rating
}
}
}
constructor(mId: Long?, mOverview: String?, mPosterPath: String?, mTitle: String?, mVoteAverage: Double?) {
this.mId = mId
this.mOverview = mOverview
this.mPosterPath = mPosterPath
this.mTitle = mTitle
this.mVoteAverage = mVoteAverage
}
constructor()
#PrimaryKey
#SerializedName("id")
var mId: Long? = null
#SerializedName("overview")
var mOverview: String? = null
#SerializedName("poster_path")
var mPosterPath: String? = null
#SerializedName("title")
var mTitle: String? = null
#SerializedName("vote_average")
var mVoteAverage: Double? = null
}
Then finally, in my adapter class, I tried to bind the item layout.
class ResultAdapter(private val context: Context) : PagedListAdapter<Result, ResultAdapter.ResultViewHolder>(DIFF_CALLBACK) {
public lateinit var mBinding: ItemActivitymainBinding
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ResultViewHolder {
mBinding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.item_activitymain, parent, false)
return ResultViewHolder(mBinding)
}
override fun onBindViewHolder(holder: ResultViewHolder, position: Int) {
val result = getItem(position)
if (result != null) {
holder.itemActivitymainBinding.titleTxt.text = result.mTitle
}
}
class ResultViewHolder(itemView: ItemActivitymainBinding) : RecyclerView.ViewHolder(itemView.root) {
var itemActivitymainBinding: ItemActivitymainBinding
var root: View
init {
root = itemView.root
itemActivitymainBinding = itemView
}
}
companion object {
const val MOVIE_ID = "MOVIE_ID"
const val MOVIE_NAME = "MOVIE_NAME"
const val MOVIE_OVERVIEW = "MOVIE_OVERVIEW"
private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<Result>() {
override fun areItemsTheSame(oldItem: Result, newItem: Result): Boolean {
return oldItem.mId === newItem.mId
}
override fun areContentsTheSame(oldItem: Result, newItem: Result): Boolean {
return oldItem == newItem
}
}
}
}
Now I am still wondering why the image doesn't display because I have read some of the blog posts about this and I followed all their procedures.
First, you binding is missing its lifecycle owner (i.e., the activity or fragment in which you use the adapter). You should pass it to your adapter and then set it:
class ResultAdapter(private val lifecycleOwner: LifecycleOwner)
: PagedListAdapter<Result, ResultAdapter.ResultViewHolder>(DIFF_CALLBACK) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ResultViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = DataBindingUtil.inflate<ItemActivitymainBinding>(inflater, R.layout.item_activitymain, parent, false)
// We set the lifecycle owner here
binding.setLifecycleOwner(lifecycleOwner)
return ResultViewHolder(binding)
}
...
}
// In your activity/fragment, pass the view as a parameter when creating the adapter
adapter = ResultAdapter(this)
(In the adapter, I have removed the property mBinding and the constructor parameter context, as neither of them were necessary.)
Second, you are defining the property movie in your layout, but you are not setting it with an actual value. To fix this, you have to update your implementation of onBindViewHolder():
override fun onBindViewHolder(holder: ResultViewHolder, position: Int) {
val movie = getItem(position)
// Here we set the layout variable "movie" with its corresponding value
holder.itemActivitymainBinding.movie = movie
}
(Please note that here I have removed the code you had written to change the title of your textview because you should change it through data-binding in the layout by doing this: android:text="#{movie.mTitle}".)
With these changes, your implementation should hopefully work!

kotlin recyclerview data not showing

Our question is how to show Parent and Child data from two SQLite DB tables?
We have two tables that are added to two ArrayLists childList and parentList.
Here are the Model Class's for each
class ModelParent {
var idD:Int = 0
var dept:String = ""
var fkD:Int = 0
var children: List<ModelChild> = mutableListOf()
//var children: ArrayList<ModelChild>? = null
//var children: List<ModelChild> by Delegates.notNull()
constructor (children: List<ModelParent>) : this()
companion object {
var globalVar = 1
}
}
class ModelChild {
var idI:Int = 0
var item:String = ""
var fkI:Int = 0
}
We have two Adapters for each table and will post that code
We are able to iterate through the two ArrayList with this code and display the data in the format we would like to show in the ViewActivity.
fun theGET(){
val db = DBHelper(this)
childList = db.queryITEM()
parentList = db.queryDEPT()
var PL = parentList.size
do {
var DEPT: String = parentList[z].dept
var PARENT_LIST_FK = parentList.get(z).fkD
println("========== Dept " + DEPT + " fkD " + PARENT_LIST_FK)
val FK = PARENT_LIST_FK
childList = db.queryALL(FK)
var CL = childList.size
for (a in 0..CL - 1) {
var CHILD_ITEM = childList[a].item
var CHILD_LIST_FK = childList[a].fkI
println("========== item " + CHILD_ITEM+" fkI "+CHILD_LIST_FK)
}
z++
}
while (z <= PL-1)
}
We will post the View Activity
class ViewActivity : AppCompatActivity() {
lateinit var recyclerView: RecyclerView
private var parentList:List<ModelParent> = ArrayList()
private var childList:List<ModelChild> = ArrayList()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_view)
initRecycler()
}// end onCreate
private fun initRecycler() {
val db = DBHelper(this)
childList = db.queryITEM()
parentList = db.queryDEPT()
recyclerView = rv_parent
recyclerView.apply{
layoutManager = LinearLayoutManager(this#ViewActivity, LinearLayout.VERTICAL, false)
adapter = ViewAdapter(parentList)
adapter = ViewChildAdapter(children = childList)
}
}
}
ViewActivity has this XML file
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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=".ViewActivity">
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_parent"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.constraint.ConstraintLayout>
The Two Adapters and coresponding XML files
class ViewAdapter(private val parents:List<ModelParent>):RecyclerView.Adapter<ViewAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.the_view,parent,false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return parents.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val parent = parents[position]
holder.textView.text = parent.dept
holder.recyclerView.apply {
layoutManager = LinearLayoutManager(holder.recyclerView.context, LinearLayout.VERTICAL, false) as RecyclerView.LayoutManager?
adapter = ViewChildAdapter(parent.children!!)
}
}
inner class ViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView){
val recyclerView : RecyclerView = itemView.rv_child
val textView: TextView = itemView.textView
}
}
class ViewChildAdapter(private val children:List<ModelChild>):RecyclerView.Adapter<ViewChildAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.child_recycler,parent,false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return children.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val child = children[position]
holder.textView.text = child.item
}
inner class ViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView){
val textView : TextView = itemView.child_textView
}
}
Inflated XML files
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="2dp"
card_view:cardBackgroundColor="#fff"
card_view:cardCornerRadius="5dp"
card_view:cardElevation="4dp"
card_view:cardUseCompatPadding="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/textView"
style="#style/Base.TextAppearance.AppCompat.Subhead"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignStart="#+id/rv_child"
android:layout_alignParentTop="true"
android:padding="20dp"
android:background="#color/color_super_lightGray"
android:text="Dept Header"
android:textColor="#color/color_Purple"
android:textSize="24sp"
android:textStyle="bold" />
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_child"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_marginTop="70dp"
android:layout_marginBottom="0dp"
android:orientation="horizontal"
android:paddingLeft="4dp"
android:paddingTop="8dp"
tools:layout_editor_absoluteX="74dp" />
</RelativeLayout>
</android.support.v7.widget.CardView>
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="#+id/child_textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginStart="32dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:background="#color/color_Transparent"
android:padding="10dp"
android:text="TextView"
android:textColor="#color/color_Black"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
When the ViewActivity is loaded ONLY the childList is displayed.
We have tried various changes and can not display the parent List though using theGET fun the parentList data is displayed so we know it is in the list.
We can run the fun theGET and crate a new ArrayList that seems futile.
Our concern is that the parentList is displayed and then removed when the childList is displayed.
We do not know how to prove this.
So our question is how to show Parent and Child data in a organized fashion in the View Activity?
We are adding New CODE based on #Cruces answer
Some issues with this code are beyond out understanding
1. We have no way to run the fun join to create the newList
2. Parent and Child ViewHolder can be called only with receiver of containing Class
3. Too many inner Class's and do we need an Outer Nested annotation?
4. or if both parent and child implement an interface a List< IItem > )
We do not know how to write an interface and connect it to the JoinAdapter
While the answer poses new question we feel it better to ask with in this context = Context HUMOR
Here is the FIX for the JoinAdapter
class JoinAdapter(internal var context: Context, val parents: List<ModelParent>) : RecyclerView.Adapter<JoinAdapter.MyViewHolder>() {
val items = mutableListOf<Any>()
init {
parents //parents should be passed as a constructor argument
.forEach {
items.add(it)
items.addAll(it.children)
}
}
override fun getItemCount(): Int = items.size;
fun getItem(position: Int): Any = items[position]
override fun getItemViewType(position: Int): Int = if (getItem(position) is ModelParent) 0 else 1
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
var view: View? = null
if (viewType == 0) {
view = LayoutInflater.from(parent.context).inflate(R.layout.the_view, parent, false)
return ParentViewHolder(view!!)
} else {
view = LayoutInflater.from(parent.context).inflate(R.layout.child_recycler, parent, false)
return ChildViewHolder(view!!)
}
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) = holder.bindData(position, getItem(position))
inner abstract class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) {
abstract fun bindData(position: Int, item: Any)
}
inner class ParentViewHolder(view: View) : MyViewHolder(view) {
override fun bindData(position: Int, item: Any) {
val parent = item as? ModelParent ?: return
parent.dept
parent.fkD
parent.children
//bind the data here
}
init {
val textView: TextView = view.textView
var editCLICK: RelativeLayout = view.findViewById(R.id.editCLICK) as RelativeLayout
//do the view setup here
}
}
inner class ChildViewHolder(view: View) : MyViewHolder(view) {
init {
val textView : TextView = itemView.child_textView
//do the view setup here
}
override fun bindData(position: Int, item: Any) {
val child = item as? ModelChild ?: return
child.item
child.idI
//bind the data here
}
}
I am going to post the View Activity call to Join Adapter
Code does not FAIL it just shows nothing?
RecyclerAdapter1 = JoinAdapter(parents = ArrayList(),context = applicationContext)
(recyclerView as RecyclerView).adapter = RecyclerAdapter1
Here is the ViewJoinActivity it will load the Parent Data NO Child Data
class ViewJoinActivity : AppCompatActivity() {
lateinit var recyclerView: RecyclerView
private var RecyclerAdapter: JoinAdapter? = null
private var linearLayoutManager: LinearLayoutManager? = null
private val db = DBHelper(this)
private var parentList:List<ModelParent> = ArrayList()
private var childList:List<ModelChild> = ArrayList()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_view_join)
initRecycler()
}// end onCreate
override fun onResume() {
super.onResume()
initDB()
}
private fun initDB() {
parentList = db.queryDEPT()
//childList = db.queryCHILD(1)
childList = db.queryITEM()
// queryCHILD only selects records with a fkI equal to idD
// SEE THE ModelChild and ModelParent
if(parentList.isEmpty()){
title = "No Records in DB"
}else{
title = "Parent List"
}
RecyclerAdapter = JoinAdapter(parents = parentList, context = applicationContext)
(recyclerView as RecyclerView).adapter = RecyclerAdapter
}
private fun initRecycler() {
val db = DBHelper(this)
childList = db.queryITEM()
parentList = db.queryDEPT()
//recyclerView = rv_parent
/*var PL = parentList.size
newList.clear()
do {
var DEPT: String = parentList[z].dept
var ND:String = DEPT
var PARENT_LIST_FK = parentList.get(z).fkD
var PL_ST = ND+" "+PARENT_LIST_FK
newList.add(PL_ST)
println("========== Dept " + DEPT + " fkD " + PARENT_LIST_FK)
val FK = PARENT_LIST_FK
childList = db.queryCHILD(FK)
var CL = childList.size
for (a in 0..CL - 1) {
var CHILD_ITEM = childList[a].item
var NI:String = childList[a].item
var CHILD_LIST_FK = childList[a].fkI
var IL_ST = NI+" "+CHILD_LIST_FK
newList.add(IL_ST)
println("========== item " + CHILD_ITEM+" fkI "+CHILD_LIST_FK)
}
z++
g++
}
while (z <= PL-1)
var ui = newList.size
g=0
for(g in 0..ui-1){
var N2 = newList[g]
if(N2.toString().contains("1")){
println("********************** We Found "+N2)
}
println("############### BOTH = "+N2)
}*/
recyclerView = this.findViewById(R.id.rv_parent)
RecyclerAdapter = JoinAdapter(parents = parentList, context = applicationContext)
linearLayoutManager = LinearLayoutManager(applicationContext)
(recyclerView as RecyclerView).layoutManager = linearLayoutManager!!
//recyclerView.apply {
//layoutManager = LinearLayoutManager(this#ViewJoinActivity, LinearLayout.VERTICAL, false)
//adapter = JoinAdapter(children = childList)
//}
}
}
Calling the Join Adapter from a Activity is the issue? ?
This Activity has a XML associated file with a RecyclerView rv_parent
The way I would do it is flatten the list edit: like this in the constructor
val items : MutableList<Any> = mutableListOf<Any>()
init() {
parents //parents should be passed as a constructor argument
.asSequence() //this is only needed if you want to also order them
.sortedBy { it.idD } //again only if you want to sort them
.forEach {
items.add(it)
items.addAll(it.children)
}
}
I would create a List < Any > (or if both parent and child implement an interface a List< IItem > ) that would contain all the data as you wish to see it, so for example it could look like this:
val items : List<Any> = listOf(parent1, child11,child12,child13,parent2,child12,child13,child14.....etc)
then I would implement a single adapter with multiple view types like this:
override fun getItemCount(): Int {
return items.size
}
fun getItem(position: Int) : Any { //or the interface
return items[position]
}
override getItemViewType (position: Int) : Int {
if (getItem(position) is ModelParent)
return 0
return 1
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
var view : View? = null
if (viewType == 0) {
view = LayoutInflater.from(parent.context).inflate(R.layout.parent_layout,parent,false)
return ParentViewHolder(view);
} else {
view = LayoutInflater.from(parent.context).inflate(R.layout.child_layout,parent,false)
return ChildViewHolder(view);
}
}
and then I would use two view holders to represent how the data is shown for the specific item
inner class ParentViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView){ ...}
inner class ChildViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView){ ...}
after that I could perform different bindings by getting the type of the view ,something like this:
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
if (getItemType(position) == 0) {
(holder as ParentViewHolder).bindData(....)
} else {
(holder as ChildViewHolder).bindData(....)
}
}
edit: Here is the complete adapter I built, it is based on two layout files:
list_item_child:
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="2dp"
card_view:cardBackgroundColor="#fff"
card_view:cardCornerRadius="5dp"
card_view:cardElevation="4dp"
card_view:cardUseCompatPadding="true">
<TextView
android:id="#+id/child_item"
style="#style/Base.TextAppearance.AppCompat.Display3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:padding="20dp"
android:textSize="24sp"
android:textStyle="bold"
tools:text="Dept Header" />
</android.support.v7.widget.CardView>
list_item_parent:
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="2dp"
card_view:cardBackgroundColor="#fff"
card_view:cardCornerRadius="5dp"
card_view:cardElevation="4dp"
card_view:cardUseCompatPadding="true">
<TextView
android:id="#+id/parent_department"
style="#style/Base.TextAppearance.AppCompat.Headline"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:padding="20dp"
tools:text="Dept Header"
android:textSize="24sp"
android:textStyle="bold" />
</android.support.v7.widget.CardView>
and the adapter would look something like this:
import android.content.Context
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
data class ModelParent(val id: Int, val children: List<ModelChild>)
data class ModelChild(val id: Int)
class JoinAdapter(internal var context: Context, val parents: List<ModelParent>) : RecyclerView.Adapter<JoinAdapter.MyViewHolder>() {
val items = mutableListOf<Any>()
init {
parents //parents should be passed as a constructor argument
.forEach {
items.add(it)
items.addAll(it.children)
}
}
override fun getItemCount(): Int = items.size;
fun getItem(position: Int): Any = items[position]
override fun getItemViewType(position: Int): Int = if (getItem(position) is ModelParent) 0 else 1
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
var view: View? = null
if (viewType == 0) {
view = LayoutInflater.from(parent.context).inflate(R.layout.rv_list_item_parent, parent, false)
return ParentViewHolder(view!!)
} else {
view = LayoutInflater.from(parent.context).inflate(R.layout.rv_list_item_child, parent, false)
return ChildViewHolder(view!!)
}
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) = holder.bindData(position, getItem(position))
inner abstract class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) {
abstract fun bindData(position: Int, item: Any)
}
inner class ParentViewHolder(view: View) : MyViewHolder(view) {
var parentDept: TextView = view.findViewById(R.id.parent_department) as TextView
override fun bindData(position: Int, item: Any) {
val parent = item as? ModelParent ?: return
parentDept.text = parent.dept
}
}
inner class ChildViewHolder(view: View) : MyViewHolder(view) {
var childItem: TextView = view.findViewById(R.id.child_item) as TextView
override fun bindData(position: Int, item: Any) {
val child = item as? ModelChild ?: return
childItem.text = child.item
}
}
}
this when used on a single recyclerview will display all children under their parent in a list
Here is a answer and some observations about the design of this app
The answer does NOT place both the parent and child data on the same Recycler View List But the answer may help to solve the issue With further exploration!
What we did was create the parent list and when the Parent Dept is clicked on the corresponding Child Items will be displayed. This may be a more functional design while shopping you only need to look at Produce items while in that section. This means less scrolling through a single master list of Parents and Children.
A word or two about the design we are guessing a grocery store might have 20 or more Departments (Parents) so how you plan to know which Items (Child data) is connected to the appropriate Dept (Parent) needs drastic redesign when building these two lists.
If you downloaded the code from GitHub you will have a better grasp about this design deficiency
Here is all the code with the XML files
Main Activity navigates to View Activity
fun onViewAll(view: View){
val intent = Intent(this,ViewActivity::class.java)
intent.putExtra("pickADAPTER",2)
startActivity(intent)
}
Here is the View Activity
class ViewActivity : AppCompatActivity() {
lateinit var recyclerView: RecyclerView
private var RecyclerAdapter1: ViewAdapter? = null
private var RecyclerAdapter2: ViewChildAdapter? = null
private var linearLayoutManager: LinearLayoutManager? = null
private val db = DBHelper(this)
private var parentList:List<ModelParent> = ArrayList()
private var childList:List<ModelChild> = ArrayList()
var idD = 0
var whichADAPTER = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_view)
val bundle: Bundle = intent.extras
idD = bundle.getInt("BIGi", 0)
whichADAPTER = bundle.getInt("pickADAPTER",0)
initRecycler()
}// end onCreate
override fun onResume() {
super.onResume()
initDB()
}
private fun initDB() {
parentList = db.queryDEPT()
childList = db.queryCHILD(idD)
// queryCHILD only selects records with a fkI equal to idD
// SEE THE ModelChild and ModelParent
if(parentList.isEmpty()){
title = "No Records in DB"
}else{
title = "Parent List"
}
if(whichADAPTER == 2) {
RecyclerAdapter1 = ViewAdapter(parents = parentList, context = applicationContext)
(recyclerView as RecyclerView).adapter = RecyclerAdapter1
}else{
RecyclerAdapter2 = ViewChildAdapter(children = childList)
(recyclerView as RecyclerView).adapter = RecyclerAdapter2
}
}
private fun initRecycler() {
val db = DBHelper(this)
childList = db.queryITEM()
parentList = db.queryDEPT()
recyclerView = rv_parent
recyclerView = this.findViewById(R.id.rv_parent)
RecyclerAdapter1 = ViewAdapter(parents = parentList, context = applicationContext)
linearLayoutManager = LinearLayoutManager(applicationContext)
(recyclerView as RecyclerView).layoutManager = linearLayoutManager!!
}
Here the XML file for View Activity
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_parent"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Here is the View Adapter
class ViewAdapter(private val parents: List<ModelParent>, internal var context: Context):RecyclerView.Adapter<ViewAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.the_view,parent,false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return parents.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val parent = parents[position]
holder.textView.text = parent.dept
holder.editCLICK.setOnClickListener {
val i = Intent(context, ViewActivity::class.java)
i.putExtra("BIGi",parent.idD)
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
context.startActivity(i)
}
}
inner class ViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView){
//val recyclerView : RecyclerView = itemView.rv_child
val textView: TextView = itemView.textView
var editCLICK: RelativeLayout = itemView.findViewById(R.id.editCLICK) as
RelativeLayout
And the inflated XML
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="2dp"
card_view:cardBackgroundColor="#FF0000"
card_view:cardCornerRadius="5dp"
card_view:cardElevation="4dp"
card_view:cardUseCompatPadding="true">
<RelativeLayout
android:id="#+id/editCLICK"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/textView"
style="#style/Base.TextAppearance.AppCompat.Subhead"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignStart="#+id/rv_child"
android:layout_alignParentTop="true"
android:padding="10dp"
android:background="#color/color_lightGray"
android:text="Dept Header"
android:textColor="#color/color_Purple"
android:textSize="24sp"
android:textStyle="bold" />
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_child"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_marginTop="50dp"
android:layout_marginBottom="0dp"
android:orientation="horizontal"
android:paddingLeft="4dp"
android:paddingTop="6dp"
tools:layout_editor_absoluteX="74dp" />
</RelativeLayout>
This is the search routine in DBHelper
fun queryCHILD(fkI: Int): List<ModelChild> {
val db = this.writableDatabase
val childList = ArrayList<ModelChild>()
val selectQuery = "SELECT * FROM $CHILD_TABLE WHERE $colCFK = ?"
val cursor = db.rawQuery(selectQuery, arrayOf(fkI.toString()))
if (cursor != null) {
if (cursor.moveToFirst()) {
do {
val contact = ModelChild()
contact.idI = Integer.parseInt(cursor.getString(cursor.getColumnIndex(colidI)))
contact.item = cursor.getString(cursor.getColumnIndex(colItem))
contact.fkI = Integer.parseInt(cursor.getString(cursor.getColumnIndex(colCFK)))
childList.add(contact)
} while (cursor.moveToNext())
}
}
cursor.close()
return childList
}
One thing to make note of we attached the OnClickListener to a Relative Layout
holder.editCLICK.setOnClickListener
Why we are not sure you can obtain parent.idD type information from a RecyclerView set as a listener?
We need to explore this but in our testing the code failed when we tried.
In the ViewActivity class, you have first set the recyclerView adapter to ViewAdapter and then to ViewChildAdapter thus, now, the adapter of recyclerView is ViewChildAdapter instead of ViewAdapter. Remove this line and the problem will be resolved.

Categories

Resources