Sending data from recyclerview to fragment without intarface in Kotlin - android

I'm studying kotlin, and am stuck about recyclerview.
The task is simple: show data from recycler (inside activity) item clicked inside a fragment.
The Model:
data class MyModel (
val info1:String,
val info2:String,
val info3:String)
the recyclerView is implemented using the idea I saw in Antonio's book (kotlin for android developers) - no intarface is used:
class RecyclerAdapter(
val myList:List<MyModel>,
val listener:(MyModel)->Unit):RecyclerView.Adapter<RecyclerAdapter.MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val itemViewholder = LayoutInflater.from(parent.context).inflate(R.layout.recycler_item,parent,false)
return MyViewHolder(itemViewholder)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bind(myList[position],listener)
}
override fun getItemCount(): Int {
return myList.count()
}
class MyViewHolder(itemView:View):RecyclerView.ViewHolder(itemView){
fun bind(list:MyModel,itemListener: (MyModel) -> Unit) = with(itemView){
recycler_infor1.text = list.info1
recicler_infor2.text = list.info2
setOnClickListener { itemListener(list) }
}
}}
In Activity:
with(my_recyclerView){
layoutManager = LinearLayoutManager(this#MainActivity,RecyclerView.VERTICAL,false)
setHasFixedSize(true)
adapter = RecyclerAdapter(fakeItens()){
supportFragmentManager.commit {
replace(R.id.fragment_container,FragmentDetail()).addToBackStack(null)
}
}
}
When the app is run, the recyclerView shows in each item the first and second information as well.
Now, I need to show these informations and the third infor inside a Fragment that has three textView:
android:id="#+id/frag_infor1"
android:id="#+id/frag_infor2"
android:id="#+id/frag_infor3"
How can I do this?

Thank's to null_override, I found my solution:
1 - make MyModel Parcelable
data class MyModel(val info1:String?,
val info2:String?,
val info3:String?
):Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readString(),
parcel.readString()
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(info1)
parcel.writeString(info2)
parcel.writeString(info3)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<MyModel> {
override fun createFromParcel(parcel: Parcel): MyModel {
return MyModel(parcel)
}
override fun newArray(size: Int): Array<MyModel?> {
return arrayOfNulls(size)
}
}
}
2 - passing to bundle and set argument to Fragment using apply in both
with(my_recyclerView){
layoutManager = LinearLayoutManager(this#MainActivity,RecyclerView.VERTICAL,false)
setHasFixedSize(true)
adapter = RecyclerAdapter(fakeItens()){
val bundle = Bundle().apply { putParcelable("Key", it) }
supportFragmentManager.commit {
replace(R.id.fragment_container,FragmentDetail().apply { arguments = bundle }).addToBackStack(null)
}
}
}
3 - get data in Fragment
lateinit var data:MyModel
override fun onAttach(context: Context) {
super.onAttach(context)
arguments?.getParcelable<MyModel>("Key").let {
if (it != null) {
data = it
}
}
}
4 - bind views
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
frag_infor1.text = data.info1
frag_infor2.text = data.info2
frag_infor3.text = data.info3
}

Related

ListAdapter submitlist not update after deleting the data instead its giving me duplicate data

when i try to delete first row i get first row back and with duplicate second row
enter image description here
after delete any row from the list gives me duplicate data like this
enter image description here
This is my Adapter class. On my deleteItem function position is passed from fragment class and
it is supposed to delete an item from the given position and update the list but its rendering the duplicate data.
class MyListAdapter :ListAdapter<Article,MyListAdapter.MyViewHolder>(MyDiffUtil()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.recycler_item,parent,false)
return MyViewHolder(view)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val item = getItem(position)
holder.onBind(item)
// to click each item of list
holder.itemView.setOnClickListener {
onItemClickListener?.let {it(item) }
}
}
class MyViewHolder(itemView :View) : RecyclerView.ViewHolder(itemView)
{
fun onBind(article: Article) = with(itemView)
{
Glide.with(this)
.load(article.urlToImage)
.error(R.drawable.notfound)
.into(imageView)
webSource.text = article.source?.name
newsDate.text = article.publishedAt
newsTitle.text = article.title
newsDescription.text = article.description
}
}
// lamda function for handling web view
private var onItemClickListener : ((Article) -> Unit)? = null
fun setOnItemClickListener(listener : (Article) ->Unit)
{
onItemClickListener = listener
}
// implementing diffutil class
class MyDiffUtil : DiffUtil.ItemCallback<Article>()
{
override fun areItemsTheSame(oldItem: Article, newItem: Article): Boolean {
return oldItem.url == newItem.url
}
override fun areContentsTheSame(oldItem: Article, newItem: Article): Boolean {
return oldItem == newItem
}
}
fun deleteItem(pos : Int)
{
var myl = ArrayList<Article>()
val currentList= currentList.toMutableList()
currentList.removeAt(pos)
myl.addAll(currentList)
submitList(myl)
}
}
`
I tried to delete the saved news from the ListAdapter and update the recycler view with animation of DiffUtill class but its not updating the recycler view and
giving duplicate data . How can i delete data with diffutil animation as its normal way. Thanks in advance.
this is my fragment
package com.example.news.Fragments
class SavedNews : Fragment() {
lateinit var mymainViewModel: MainViewModel
lateinit var databaseObject: MyDataBase
lateinit var myAdapter: MyListAdapter
lateinit var convertedArticleList : ArrayList<Article>
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
myAdapter = MyListAdapter()
convertedArticleList = ArrayList()
return inflater.inflate(R.layout.fragment_saved_news, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
savedNewsRecyclerView.layoutManager = LinearLayoutManager(activity,LinearLayoutManager.VERTICAL,
false)
savedNewsRecyclerView.adapter = myAdapter
ItemTouchHelper(object :ItemTouchHelper.SimpleCallback(0,ItemTouchHelper.RIGHT){
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
// this method is called
// when the item is moved.
return true
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
// this method is called when we swipe our item to right direction.
// on below line we are getting the item at a particular position.
val deletedCourse: Article =
convertedArticleList.get(viewHolder.adapterPosition)
myAdapter.deleteItem(viewHolder.adapterPosition)
mymainViewModel.deleteSavedNews(deletedCourse.id!!)
// myAdapter.notifyItemRemoved(viewHolder.adapterPosition)
// myAdapter.submitList(myCurrentList)
// Snackbar.make(savedNewsRecyclerView,"Deleted" + deletedCourse.title,
// Snackbar.LENGTH_LONG).setAction(
// "Undo",
// View.OnClickListener {
//
// convertedArticleList.add(position,deletedCourse)
// myAdapter.notifyItemInserted(position)
// }
// ).show()
}
}).attachToRecyclerView(savedNewsRecyclerView)
}
override fun onResume() {
super.onResume()
Log.d("LIFE","ON Resume")
val myInterfaceObject = ApiInterface.MyObject.getInstance()
databaseObject = MyDataBase.MyObjectDB.getDBInstance(activity as MainActivity)
val myRepository = Repository(myInterfaceObject, databaseObject)
mymainViewModel = ViewModelProvider(
this,
MainViewModelFactory(myRepository)
).get(MainViewModel::class.java)
//listAdapter things
// show saved news in savednews fragment
lifecycleScope.launch(Dispatchers.Main) {
//abstract data from saved room database and converting likedartcile datacass object to
// Artticle data class article
mymainViewModel.abstractSavedNews().observe(viewLifecycleOwner, Observer {
it.forEach { eachLikedArticle ->
val obj = toArticle(eachLikedArticle)
convertedArticleList.add(obj)
}
myAdapter.submitList(convertedArticleList)
})
//clicking the item of save news
myAdapter.setOnItemClickListener {
val bundle = Bundle().apply {
putSerializable("article", it)
}
convertedArticleList.clear()
findNavController().navigate(R.id.action_savedNews_to_article, bundle)
}
}
}
private fun toArticle(rawObject: LikedArticle) = Article(
rawObject.author, rawObject.content,
rawObject.description, rawObject.publishedAt, rawObject.source, rawObject.title,
rawObject.url, rawObject.urlToImage, rawObject.id
)
}
There is not enough information to actually replicate how you're trying to use this in your Fragment/Activity but without changing your code too much, this works (note I used view binding):
class MyListAdapter :
ListAdapter<Article, MyViewHolder>(MyDiffUtil()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = MyViewHolder(
RecyclerItemBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val item = getItem(position)
holder.onBind(item)
}
fun deleteItem(pos: Int) {
var myl = ArrayList<Article>()
val currentList = currentList.toMutableList()
currentList.removeAt(pos)
myl.addAll(currentList)
submitList(myl)
}
}
class MyViewHolder(private val binding: RecyclerItemBinding) : RecyclerView.ViewHolder(binding.root) {
fun onBind(article: Article) = with(binding) {
textView.text = article.url
}
}
class MyDiffUtil : DiffUtil.ItemCallback<Article>() {
override fun areItemsTheSame(oldItem: Article, newItem: Article): Boolean {
return oldItem.url == newItem.url
}
override fun areContentsTheSame(oldItem: Article, newItem: Article): Boolean {
return oldItem == newItem
}
}
Overall this should work.
You can also refactor deleteItem to something more meaningful:
fun deleteItem(pos: Int) {
val oldList = currentList.toMutableList()
oldList.removeAt(pos)
val updatedList = oldList
submitList(updatedList)
}

RecyclerView swipe functionality breaks after orientation change

I created a RecyclerView that refreshes its list based on a database call. Each row has an options menu that is revealed when the user swipes. My original issue was that after an orientation change, the swipe gestures no longer revealed the menu. I hit all my expected breakpoints with onCreateViewHolder() and the onSwipe(). However, the row remained as the HIDE_MENU view type after swiping.
So I tried to introduce LiveData to persist the state of the list after orientation changes. The RecyclerView was still created and populated with items but now the swipe gesture crashes the application with an error:
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
Do I need to use LiveData to fix the original issue of preserving my swipe functionality after orientation changes? If not, please can someone explain why the item view types are no longer updated after orientation changes.
If I do need to use a ViewModel, what am I doing that is causing the list adapter not to receive the updated list?
HistoryFragment
class HistoryFragment : Fragment() {
private val historyViewModel by activityViewModels<HistoryViewModel>()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val root = inflater.inflate(R.layout.fragment_history, container, false)
historyViewModel.getHistoryList().observe(viewLifecycleOwner, {
refreshRecyclerView(it)
})
return root
}
private fun updateHistoryList() {
val dbHandler = MySQLLiteDBHandler(requireContext(), null)
val historyList = dbHandler.getHistoryList() as MutableList<HistoryObject>
historyViewModel.setHistoryList(historyList)
}
private fun refreshRecyclerView(historyList: MutableList<HistoryObject>) {
val historyListAdapter = HistoryListAdapter(historyList)
val callback = HistorySwipeHelper(historyListAdapter)
val helper = ItemTouchHelper(callback)
history_list.adapter = historyListAdapter
helper.attachToRecyclerView(history_list)
}
private fun setupSort() {
val sortSpinner: Spinner = history_list_controls_sort
sortSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) {}
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
updateHistoryList()
}
}
}
override fun onViewCreated(
view: View,
savedInstanceState: Bundle?
) {
setupSort()
}
}
HistoryListAdapter
const val SHOW_MENU = 1
const val HIDE_MENU = 2
class HistoryListAdapter(private var historyData: MutableList<HistoryObject>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == SHOW_MENU) {
val inflatedView = LayoutInflater.from(parent.context).inflate(R.layout.history_list_view_row_items_menu, parent, false)
MenuViewHolder(inflatedView)
} else {
val inflatedView = LayoutInflater.from(parent.context).inflate(R.layout.history_list_view_row_items_description, parent, false)
HistoryItemViewHolder(inflatedView)
}
}
override fun getItemViewType(position: Int): Int {
return if (historyData[position].showMenu) {
SHOW_MENU
} else {
HIDE_MENU
}
}
override fun getItemCount(): Int {
return historyData.count()
}
fun showMenu(position: Int) {
historyData.forEachIndexed { idx, it ->
if (it.showMenu) {
it.showMenu = false
notifyItemChanged(idx)
}
}
historyData[position].showMenu = true
notifyItemChanged(position)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val item: HistoryObject = historyData[position]
if (holder is HistoryItemViewHolder) {
holder.bindItem(item)
...
}
if (holder is MenuViewHolder) {
holder.bindItem(item)
...
}
}
class HistoryItemViewHolder(v: View, private val clickHandler: (item: HistoryObject) -> Unit) : RecyclerView.ViewHolder(v) {
private var view: View = v
private var item: HistoryObject? = null
fun bindItem(item: HistoryObject) {
this.item = item
...
}
}
class MenuViewHolder(v: View, private val deleteHandler: (item: HistoryObject) -> Unit) : RecyclerView.ViewHolder(v) {
private var view: View = v
private var item: HistoryObject? = null
fun bindItem(item: HistoryObject) {
this.item = item
...
}
}
}
HistorySwipeHelper
class HistorySwipeHelper(private val adapter: HistoryListAdapter) : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean { return false }
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
adapter.showMenu(viewHolder.adapterPosition)
}
override fun getSwipeThreshold(viewHolder: RecyclerView.ViewHolder): Float {
return 0.1f
}
}
HistoryViewModel
class HistoryViewModel(private var historyListHandle: SavedStateHandle) : ViewModel() {
fun getHistoryList(): LiveData<MutableList<HistoryObject>> {
return historyListHandle.getLiveData(HISTORY_LIST_KEY)
}
fun setHistoryList(newHistoryList: MutableList<HistoryObject>) {
historyListHandle.set(HISTORY_LIST_KEY, newHistoryList)
}
companion object {
const val HISTORY_LIST_KEY = "MY_HISTORY_LIST"
}
}
Activity
class MainActivity : AppCompatActivity() {
private val historyViewModel: HistoryViewModel by lazy {
ViewModelProvider(this).get(HistoryViewModel::class.java)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
historyViewModel.setHistoryList(mutableListOf())
}
}
Thanks in advance. If this question is too broad I can try again and decompose it.
You shouldn't create new adapter every time you get an update of your history list. Keep using the same adapter, just update the items and call notifyDataSetChanged() to update the state (of course you can use different methods to notify about the insertion/deletion/etc, but make it work with notifyDataSetChanged() first).
I'm pretty sure this will fix the issue.

android - RecyclerView and OnItemClick: No value passed for parameter 'listener'

What's the objective
Im currently working on an app which has a RecyclerView for the Settings menu. This menu serves to load other fragments. So i needed to implement an OnItemClick function: for this, i followed this video.
What's the probelm
Following the given tutorial, Android Studio flags val adapter = adapterSettings(settingsList), saying No value passed for parameter 'listener'. I suppose that im missing something, since without the code written in the tutorial, the RecyclerView works.
So, am i missing something? Are there any ways to fix this in an easy and clean way?
Code:
activitySettings.kt
class ndActSettings : AppCompatActivity(), adapterSettings.OnItemClickListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.ndactivity_settings)
topToolbarBack.setNavigationOnClickListener {
finish()
}
var settingsList = listOf(
dataItemsSettings(getString(R.string.look), getString(R.string.lookdescription), R.drawable.ic_colored_color_lens),
dataItemsSettings(getString(R.string.reproduction), getString(R.string.reproductiondescription), R.drawable.ic_colored_view_carousel),
dataItemsSettings(getString(R.string.images), getString(R.string.imagesdscription), R.drawable.ic_colored_image),
dataItemsSettings(getString(R.string.audio), getString(R.string.audiodescription), R.drawable.ic_colored_volume_up),
dataItemsSettings(getString(R.string.about), getString(R.string.aboutdescription), R.drawable.ic_colored_info)
)
val adapter = adapterSettings(settingsList) //ERROR HERE!
rvSettings.adapter = adapter
rvSettings.layoutManager = LinearLayoutManager(this)
}
override fun OnItemClick(position: Int) {
//TODO
}
}
adapterSettings.kt
class adapterSettings(
var settingsList: List<dataItemsSettings>,
var listener: OnItemClickListener
) : RecyclerView.Adapter<adapterSettings.SettingsViewHolder>() {
inner class SettingsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
init {
itemView.setOnClickListener(this)
}
override fun onClick(p0: View?) {
val position : Int = adapterPosition
if (position != RecyclerView.NO_POSITION) {
listener.OnItemClick(position)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SettingsViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_settings, parent, false)
return SettingsViewHolder(view)
}
override fun getItemCount(): Int {
return settingsList.size
}
override fun onBindViewHolder(holder: SettingsViewHolder, position: Int) {
holder.itemView.apply {
rvTitle.text = settingsList[position].stringTitle
rvDescription.text = settingsList[position].stringDescription
rvIcon.setImageResource(settingsList[position].itemIcon)
}
}
interface OnItemClickListener {
fun OnItemClick(position: Int)
}
}
The constructor of class adapterSettings is expecting two parameters
class adapterSettings(
var settingsList: List<dataItemsSettings>,
var listener: OnItemClickListener
)
However, you are instantiating the object with one parameter only:
val adapter = adapterSettings(settingsList)
So, you have to add a second parameter.. An object that implements OnItemClickListener. Since you activity already implements that interface, you can send the activity as second parameter:
val adapter = adapterSettings(settingsList, this)

callback from fragment in ViewPager2 adapter

Ok, I got the following fragment with callback there witch I'm setting to ViewPager2 adapter:
class PremiumFragment : BaseFragment(), OnPageChanged {
override fun getLogTag(): String {
return TAG
}
private lateinit var pagerCounter: ImageView
private lateinit var viewPager: ViewPager2
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewPager = view.findViewById(R.id.view_pager) as ViewPager2
viewPager.adapter = ViewPagerAdapter(this)
pagerCounter = view.findViewById(R.id.counter)
}
companion object {
const val TAG = "PremiumFragment"
fun getInstance(): BaseFragment {
Log.d(TAG, "getInstance()")
val args = Bundle()
args.putInt(ARG_LAYOUT_ID, R.layout.premium_f)
val fragment =
PremiumFragment()
fragment.arguments = args
return fragment
}
}
override fun onPageChanged() {
when (viewPager.currentItem) {
0 -> pagerCounter.setImageResource(R.drawable.circle_1)
1 -> pagerCounter.setImageResource(R.drawable.circle_2)
2 -> pagerCounter.setImageResource(R.drawable.circle_3)
}
}
}
My adapter:
class ViewPagerAdapter constructor(val callback: OnPageChanged) : RecyclerView.Adapter<PagerVH>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PagerVH =
PagerVH(LayoutInflater.from(parent.context).inflate(R.layout.viewpager_f, parent, false))
override fun getItemCount(): Int = Images.values().size
override fun onBindViewHolder(holder: PagerVH, position: Int) = holder.itemView.run {
pager_container.findViewById<ImageView>(R.id.imageView)
.setImageResource(Images.values()[position].image)
}
override fun getItemViewType(position: Int): Int {
callback.onPageChanged()
return super.getItemViewType(position)
}
companion object {
enum class Images(private val value: Int, val image: Int) {
First(0, R.drawable.wow_girl),
Second(1, R.drawable.insights_girl_2),
Third(2, R.drawable.remind_girl);
}
}
}
It should set new drawable every time we swipe ViewPager, but it changes image in fragment only once an then it is not working, have completely no idea where in adapter I should call my callback for a proper behavior, please tell me where should I call this callback? Appreciate any advices!
So I found out that you should call callback from onViewDetachedFromWindow for it calls every time you swipe fragment, and it is quite logical
override fun onViewDetachedFromWindow(holder: PagerVH) {
callback.onPageChanged()
super.onViewDetachedFromWindow(holder)
}

Recyclerview illegal state exception with data binding and viewModel

I am fetching a list of categories from an api and setting them into recyclerview . Adapter code is written in viewModel class and is called by the fragment that is calling the api. Below are the methods for setting adapters.
fun getAdapter(
listener: OtherVideoCategoriesRecyclerAdapter.OtherVideoCategoriesRecyclerAdapterListener,context: Context
): OtherVideoCategoriesRecyclerAdapter {
if (categoriesRecyclerAdapter == null)
categoriesRecyclerAdapter = OtherVideoCategoriesRecyclerAdapter(listener,context)
return categoriesRecyclerAdapter as OtherVideoCategoriesRecyclerAdapter
}
fun setItems(categories: ArrayList<OtherCategoriesItem>) {
categoriesList = categories
categoriesRecyclerAdapter!!.setItems(categoriesList!!)
}
And this is how I call these methods from my fragment class.
otherVideoViewModel.setItems(it.first.data!!.otherCategories as ArrayList<OtherCategoriesItem>)
Set Adapter method
private fun setAdapter() {
otherVideosCategoriesBinding.recyclerView.layoutManager = LinearLayoutManager(activity)
otherVideosCategoriesBinding.recyclerView.itemAnimator = DefaultItemAnimator()
adapter = otherVideoViewModel.getAdapter(adapterListener,activity!!)
otherVideosCategoriesBinding.recyclerView.adapter = adapter
}
And this is the adapter class.
class OtherVideoCategoriesRecyclerAdapter(private val listener: OtherVideoCategoriesRecyclerAdapterListener,val context: Context): RecyclerView.Adapter<OtherVideoCategoriesRecyclerAdapter.ViewHolder>() {
var categories = ArrayList<OtherCategoriesItem>()
interface OtherVideoCategoriesRecyclerAdapterListener {
fun onItemClicked(position: Int)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OtherVideoCategoriesRecyclerAdapter.ViewHolder {
val inflater=LayoutInflater.from(context)
val binding = ItemOtherVideoCategoryBinding.inflate(inflater, parent, false)
return OtherVideoCategoriesRecyclerAdapter.ViewHolder(binding)
}
override fun getItemCount(): Int {
return categories.size
}
override fun onBindViewHolder(holder: OtherVideoCategoriesRecyclerAdapter.ViewHolder, position: Int) {
val item = categories[position]
holder.bindViews(item)
}
class ViewHolder(private val binding: ItemOtherVideoCategoryBinding): RecyclerView.ViewHolder(binding.root) {
fun bindViews(model: OtherCategoriesItem){
binding.model=model
binding.executePendingBindings()
}
}
fun setItems(categoriesList: ArrayList<OtherCategoriesItem>) {
categories = categoriesList
notifyDataSetChanged()
}
}
When I run this code, it crashes with following exception.
java.lang.IllegalStateException: ViewHolder views must not be attached when created. Ensure that you are not passing 'true' to the attachToRoot parameter of LayoutInflater.inflate(..., boolean attachToRoot)
I have tried all the related answers to this error but none of them worked for my case as many of those answers doesn't included data binding.
Hey just changing your onCreateViewHolder a bit. Try this:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OtherVideoCategoriesRecyclerAdapter.ViewHolder {
val inflater=LayoutInflater.from(context)
val binding:ItemOtherVideoCategoryBinding = DataBindingUtil.inflate(inflater,R.layout.your_layout_name, parent, false)
return OtherVideoCategoriesRecyclerAdapter.ViewHolder(binding)
}

Categories

Resources