Navigation.createNavigateOnClickListener from onBindViewHolder? - android

I want to set an onclicklistener in the onBindViewHolder in order to navigate to a different fragment and send along some data to that fragment.
For the life of me, I can't seem to find a way to make it work. Any and all help is greatly appreciated!
The adapter class:
class ListAdapter(private val list: List<Workout>): RecyclerView.Adapter<WorkoutViewHolder>() {
override fun getItemCount(): Int{
return list.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WorkoutViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
return WorkoutViewHolder(layoutInflater, parent)
}
override fun onBindViewHolder(holder: WorkoutViewHolder, position: Int) {
val workout: Workout = list[position]
holder.itemView.setOnClickListener{
Toast.makeText(holder.itemView.context, "TEST", Toast.LENGTH_LONG).show()
val id = workout.workoutId
val bundle = Bundle()
bundle.putInt("workoutId", id)
Navigation.createNavigateOnClickListener(R.id.workoutDetailsFragment)
}
holder.bind(workout)
}
}
I can get the toast to pop up, so the onclicklistener seems to be working. However, the navigation part does not work.
If I just set a button inside the fragment that is hosting the recyclerview and add button.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.workoutDetailsFragment)) it can navigate just fine. So the problem seems to be calling the navigate function from inside the onclicklistener inside the onbindviewholder

Navigation.createNavigateOnClickListener() creates an OnClickListener. Creating an OnClickListener just to never set it on anything doesn't do anything.
Instead, you'll want to just trigger your navigate() call directly, doing the same one line of code that createNavigateOnClickListener does internally:
override fun onBindViewHolder(holder: WorkoutViewHolder, position: Int) {
val workout: Workout = list[position]
holder.itemView.setOnClickListener{
Toast.makeText(holder.itemView.context, "TEST", Toast.LENGTH_LONG).show()
val id = workout.workoutId
val bundle = Bundle()
bundle.putInt("workoutId", id)
// Using the Kotlin extension in the -ktx artifacts
// Alternatively, use Navigation.findNavController(holder.itemView)
holder.itemView.findNavController().navigate(
R.id.workoutDetailsFragment, bundle)
}
holder.bind(workout)
}

You need to assign your created listener rather than using it inside of a lambda. When you use a lambda with setOnClickListener(), the lambda literally is your listener. So in your example, you're creating a listener, but it's never assigned anywhere.
So to instead assign the created listener from Navigation.createNavigateOnClickListener(), your code should look like holder.itemView.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.workoutDetailsFragment))

Related

RecyclerView with databinding and onClick listener

I'm starting using Kotlin (i'm a web dev) to maintain the mobile app of my current job. To practice my learning, I'm creating a basic app which is displaying a list of France departments (using a REST Api), and I need to allow the user to click on a list item to get more info on the selected item.
I'm trying to build this with databinding, Koin as dependency injection, and Room as db layer.
My issue is that I created a RecyclerView custom Adapter, and used the databinding to give it the datas. But now I want to implement the onClick behaviour, which should launch another activity to display item details. My problem is: I don't know how to do this in a clean way.
I was thinking about creating a viewModel to link to my Adapter, but can't really find how to do it well. And even if I did, how to start another activity in a viewModel ? (don't have access to the context and startActivity function). So I finally dropped that solution that doesn't seems to fit.
So I'm currently thinking of passing directly from my adapter the onClick function, but can't find a way to bind this function in my xml file. Here is my files:
MainActivity:
class MainActivity : AppCompatActivity() {
private val mViewModel: DepartmentsViewModel by viewModel()
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.toolbar.title = "Liste des départements"
val adapter = DepartmentListAdaptater()
binding.recyclerview.adapter = adapter
binding.recyclerview.layoutManager = LinearLayoutManager(this)
mViewModel.allDepartments.observe(this, Observer { data -> adapter.submitList(data) })
}
}
RecyclerView.Adapter:
class DepartmentListAdaptater : RecyclerView.Adapter<DepartmentListAdaptater.ViewHolder>() {
private var dataSet: List<Department>? = null
inner class ViewHolder(private val binding: DepartmentListRowBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(department: Department?) {
binding.department = department
}
}
fun submitList(list: List<Department>) {
dataSet = list
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = DepartmentListRowBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding)
}
override fun getItemCount(): Int = dataSet?.size ?: 0
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(dataSet?.get(position))
}
}
The XML View:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="department" type="com.navalex.francemap.data.entity.Department" />
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="72dp">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:background="#drawable/list_item_bg"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:clickable="true"
tools:ignore="UselessParent">
<TextView
android:id="#+id/textView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingRight="16dp"
android:text="#{department.nom}"
android:paddingLeft="16dp"/>
</LinearLayout>
</RelativeLayout>
</layout>
First I want to say that it's really impressive that you are a web developer and you already have a lot of knowledge about things like dependency injection and keep the state of the view on ViewModel, congrats. Now, let's talk about your problem... I'll start with some suggestions that will improve the code clarity and performance.
For the Adapter implementation, always prefer to use ListAdapter, because this implementation have a more efficient way to compare the current list with the new list and update it. You can follow this example:
class MyAdapter: ListAdapter<ItemModel, MyAdapter.MyViewHolder>(DIFF_CALLBACK) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val binding = FragmentFirstBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return MyViewHolder(binding)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bind(getItem(position))
}
class MyViewHolder(
private val binding: FragmentFirstBinding
): RecyclerView.ViewHolder(binding.root) {
fun bind(item: ItemModel) {
// Here you can get the item values to put this values on your view
}
}
companion object {
private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<ItemModel>() {
override fun areItemsTheSame(oldItem: ItemModel, newItem: ItemModel): Boolean {
// need a unique identifier to have sure they are the same item. could be a comparison of ids. In this case, that is just a list of strings just compare like this below
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: ItemModel, newItem: ItemModel): Boolean {
// compare the objects
return oldItem == newItem
}
}
}
}
In your fragment, you have a observer, that observe the value you want to sent to the adapter, right? When a update happen, you call the submitList sending the updated list and when the adapter receive this new list, the adapter will be responsible to update just the items that changed, because of your DIFF_CALLBACK implementation.
About the onClick item, you can wait for a callback on your adapter. Doing this:
class MyAdapter(
private val onItemClicked: (item: ItemModel) -> Unit
): ListAdapter<ItemModel, MyAdapter.MyViewHolder>(DIFF_CALLBACK) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val binding = FragmentFirstBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return MyViewHolder(binding, onItemClicked)
}
// ...
class MyViewHolder(
private val binding: FragmentFirstBinding,
private val onItemClicked: (item: ItemModel) -> Unit
): RecyclerView.ViewHolder(binding.root) {
fun bind(item: ItemModel) {
// ...
// Here you set the callback to a listener
binding.root.setOnClickListener {
onItemClicked.invoke(item)
}
}
}
// ...
}
As you can see, we will receive the callback on the Adapter constructor, then we send to the ViewHolder by constructor too. And on the ViewHolder bind we set the callback to a click listener.
On you fragment, you will have something like this:
class MyFragment: Fragment() {
private lateinit var adapter: MyAdapter
private val onItemClicked: (itemModel: ItemModel) -> Unit = { itemModel ->
// do something here when the item is clicked, like redirect to another activity
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
adapter = MyAdapter(onItemClicked)
}
}
I hope it helps you. Please, let me know if you need something more. I really appreciate helping.
I don't know about data binding specifically, but a typical way to do it is to let the Activity handle details like app navigation, and let the Adapter trigger that logic. A listener function is an easy way to do this:
// in your Adapter
var clickListener: ((YourData) -> ())? = null
// in your ViewHolder (make it an inner class so it can access the Adapter's
// fields, like the listener object and the stored data)
init {
clickableView.setOnClickListener {
// pass back whatever data here, if the listener needs to know
// what's been clicked. I'm just doing a lookup and passing
// the data item currently being displayed
clickListener?.invoke(
adapterData[bindingAdapterPosition]
)
}
}
// in your Activity, when setting up the adapter
adapter.clickListener = { whateverData ->
// do what you need to do in response to the click
}
So the Activity itself is defining that logic about actions that should be taken when a click happens - it's basically wiring up different parts of the app, so the Adapter doesn't need to be concerned with anything except taking data, displaying it, and informing a listener when specific interactions take place. That listener code (defined by the Activity) could navigate somewhere else, or update a database, or pass it to a networking component... the adapter doesn't need to know about that.
(The non-Kotlin way to do this would be to create an interface and have the Activity implement that, and pass itself as the listener/callback object, that kind of thing)

Using onClickListener in Recycler View with Retrofit Structure - Kotlin

Hello i have a recyclerview that is filled with some data coming from a Webservice, using Retrofit.
Now I want to implement a onClickListener, so when i click each row of the Recycler View, i can see more data from that object, and tried to work with some examples, but i got stucked
Here is my adapter. I know that in the onCreateViewHolder, i should put in the Return AnunciosViewHolder a second parameter, of the type cellClickListener, but i have no idea what i have to put. I tried this#CellCLickListener and this#cellCLickListener and it gave me error that is is unresolved
class AnuncioAdapter(val anuncios: List<Anuncio>): RecyclerView.Adapter<AnunciosViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AnunciosViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.recyclerline, parent, false)
return AnunciosViewHolder(view)
}
override fun getItemCount(): Int {
return anuncios.size
}
override fun onBindViewHolder(holder: AnunciosViewHolder, position: Int) {
return holder.bind(anuncios[position])
}
}
class AnunciosViewHolder(itemView : View, private val cellClickListener: CellClickListener): RecyclerView.ViewHolder(itemView){
private val morada: TextView = itemView.findViewById(R.id.morada)
private val telemovel: TextView = itemView.findViewById(R.id.number)
private val fotografia: ImageView = itemView.findViewById(R.id.image)
fun bind(anuncio: Anuncio) {
morada.text = anuncio.morada
telemovel.text = anuncio.telemovel
itemView.setOnClickListener {
cellClickListener.onCellClickListener(anuncio)
}
I also tried creating an interface
interface CellClickListener {
fun onCellClickListener (data: Anuncio)
}
and in my Activity i put this method and it gives me an error that «overrides nothing»
override fun onCellClickListener(data: Anuncio) {
val intent = Intent(this#ListaAnuncios, DetalhesActivity::class.java)
intent.putExtra(PARAM_ID, data.id.toString())
intent.putExtra(PARAM_MORADA, data.morada)
intent.putExtra(PARAM_TELEMOVEL, data.telemovel)
startActivityForResult(intent, newAnuncioActivityRequestCode1)
Log.e("***ID", data.id.toString())
}
UPDATE
After using the suggestions made by Praveen i was able to clean my Adapter from errors, however i am struggling in the activity part
if it put
val anuncioAdapter = AnuncioAdapter(anuncios, this)
on the beggining of my On Create, it doesn't recognize «anuncios»
However i am declaring my adapter inside the call.enqueue
recyclerView.apply {
setHasFixedSize(true)
layoutManager =
LinearLayoutManager(this#ListaAnuncios)
adapter = AnuncioAdapter(response.body()!!)
}
And it is asking to pass an instance of cellClickListener here, but if i use «this» in here, it is stated that i am trying to pass an instance of the recycler view instead of the CellClickListener
NEW UPDATE
Forgot to put all the call.enqueue method
call.enqueue(object : Callback<List<Anuncio>> {
override fun onResponse(call: Call<List<Anuncio>>, response: Response<List<Anuncio>>) {
if (response.isSuccessful){
recyclerView.apply {
setHasFixedSize(true)
layoutManager =
LinearLayoutManager(this#ListaAnuncios)
adapter = AnuncioAdapter(response.body()!!)
}
}
}
override fun onFailure(call: Call<List<Anuncio>>, t: Throwable) {
Toast.makeText(this#ListaAnuncios, "${t.message}", Toast.LENGTH_LONG).show()
}
}) }
i tried both approaches of #Praveen and #aligur, but still struggling with asking me to put the instance of Clicklistener as the 2nd parameter, but using «this» is putting the instance of the Recycler View and not of the ClickListener
Thank You in advance
and in my Activity i put this method and it gives me an error that
«overrides nothing»
You are not implementing CellClickListener in your activity. Add CellClickListener after your activity's class name declaration
class MainActivity : AppCompatActivity(), CellClickListener {
}
I know that in the onCreateViewHolder, i should put in the Return
AnunciosViewHolder a second parameter, of the type cellClickListener,
but i have no idea what i have to put. I tried this#CellCLickListener
and this#cellCLickListener and it gave me error that is is unresolved
You've to add the private val cellClickListener: CellClickListener parameter to the constructor of AnuncioAdapter, not the ViewHolder. Only then you will be able to pass it from your activity.
Change constructor of AnuncioAdapter to accept a CellClickListener and remove the same from the constructor of AnunciosViewHolder
class AnuncioAdapter(
private val anuncios: List<Anuncio>,
private val cellClickListener: CellClickListener
): RecyclerView.Adapter<AnunciosViewHolder>() {
}
To access this cellClickListener inside AnunciosViewHolder you've to make it an inner class of AnuncioAdapter, which you can make, as it's already tightly coupled with the adapter.
inner class AnunciosViewHolder(itemView : View): RecyclerView.ViewHolder(itemView){
}
Now, on creating an object of AnuncioAdapter inside activity, just pass an instance of cellClickListener using this, as it's already implementing it.
val anuncioAdapter = AnuncioAdapter(anuncios, this)
I think the easiest way is passing function as parameter to RecyclerViewAdapter.
for instance:
RecyclerViewAdapter(val clickListener : () -> Unit)
onCreateViewHolder(){
clickListener.invoke()
}
in your view
adapter = ReceylerViewAdapter({
//do your stuff here
})
Was finally able to find a solution. By Using #Praveen suggestion, and by finding this example https://github.com/velmurugan-murugesan/Android-Example/tree/master/RetrofitWithRecyclerviewKotlin/app/src/main/java/app/com/retrofitwithrecyclerviewkotlin
On the activity i added a new val, before the OnCreate method
lateinit var anuncioAdapter: AnuncioAdapter
Added this on the onCreate (so i could use the first sugestion)
val recyclerView = findViewById<RecyclerView>(R.id.recycler_view)
anuncioAdapter = AnuncioAdapter(this,this)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = anuncioAdapter
And changed the recyclerview.apply {} on the call.enqeue just to
anuncioAdapter.Anuncios(response.body()!!);
And finally created the Anuncios Method on the Adapter
fun Anuncios(anuncio: List<Anuncio>){
this.anuncios = anuncio;
notifyDataSetChanged()
}
With this it works like how i wanted id. Thanks for the help

Kotlin how pass parameter to funcion onClick in Adapter to ViewHolder?

I have an Adapter:
class TripsAdapter(
onClickButtonAction: (TripId : Int) -> Unit,
): ListAdapter<Trip, TripssViewHolder>(TripsDiffCallBack()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TripssViewHolder {
return TripsViewHolder(
ItemsTripsBinding.inflate(
LayoutInflater.from(parent.context), parent, false), parent.context)
}
override fun onBindViewHolder(holder: TripsViewHolder, position: Int) {
holder.bind(getItem(position), onClickButtonAction ) <-- here I don't know how pass this function to ViewHolder
}
}
And here is bind function in ViewHolder:
fun bind(trip: Trip, onClickButtonAction : (Trip: Int) -> Unit) <- here is wrong code I think{
// And here I want to reaact on button click and pass ID to fragment like this:
binding.button.setOnClickListener{
onClickButtonAction.invoke()
}
}
And I want to receive it in Fragment like this:
TripsAdapter = TripsAdapter(onClickButtonAction = { id ->
do magic :P
})
Is it posible to pass this ID like funciton? I dont want to use interface. I want to pass Id on click from ViewHolder to Fragment.
You can pass a method as lambda as a callback . And since its a callback it should be Global so you do not have to pass it to ViewHolder further. Also u need to declare the lambda as val so that u can access it in the class.
I have created an example below .
class TripAdapter(val onClickButtonAction: (trip : Trip, view:View?) -> Unit) : ListAdapter<Trip, TripAdapter.TripsViewHolder>(TripsDiffCallBack) {
inner class TripsViewHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bind(trip: Trip) {
binding.button.setOnClickListener {
onClickButtonAction(trip, it)
}
}
}
}
this is how your lambda will look i have changed the parameters just in case . passing whole object of Trip and also passing the clicked View this can be helpful for handling clicks on multiple views.
Now wherever u are using this Adapter you create its as below :-
val adapter = TripAdapter(::onTripClickListener)
private fun onTripClickListener(trip:Trip, view: View?){
}

How can I get the details of a recyclerview item without the adapterPosition?

I have a recyclerView in my kotlin app that shows a list of items, when i click on one my app navigates to other fragment that shows the details of that recyclerview item, my problem is when I filter the results, it uses the adapterPosition that in this case, its different from the position of the data in the json.
When I filter the data with searchView, I submit to the adapter the new list with the filters applied.
Fragment where the recyclerview is:
(Here i would like to send as a string one of the fields shown in the recyclerview item i click)
private var museumsListAdapter=MuseumsListAdapter{ it ->
val bundle = Bundle().apply {
putInt(INDICE,it)
}
findNavController().navigate(R.id.action_ListMuseumsFragment_to_detailsMuseumFragment, bundle)
}
Adapter of the recyclerView:
class MuseumsListAdapter(private val onMuseumSelected: (Int) -> Unit):
ListAdapter<MuseumsFieldsItem, MuseumsListViewHolder>(MuseumsFieldsItem.DIFF_CALLBACK) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MuseumsListViewHolder {
val itemView=MuseumListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return MuseumsListViewHolder(itemView.root){
onMuseumSelected(it)
}
}
override fun onBindViewHolder(holder: MuseumsListViewHolder, position: Int) {
holder.bind(getItem(position))
}
}
ViewHolder of the recyclerview:
lass MuseumsListViewHolder(itemView: View, private val onItemClicked: (Int) ->Unit) : RecyclerView.ViewHolder(itemView) {
val itemBinding=MuseumListItemBinding.bind(itemView)
init {
itemView.setOnClickListener{
onItemClicked(adapterPosition)
}
}
And in the other fragment (details one) I get the value "INDICE" of the bundle.
class MuseumsListAdapter(private val onMuseumSelected: (Int) -> Unit):
this is a callback which takes in an int, so just don't use int :)
class MuseumsListAdapter(private val onMuseumSelected: (Foo) -> Unit):
where Foo represents whatever you model is, make use of Museum in your case
inside your:
itemView.setOnClickListener{
onMuseumSelected(adapterPosition)
}
you now need an instance of your Museum class.
by using private val onMuseumSelected: (Foo) -> Unit you'll get back a complete model to your fragment/activity, so you can use whatever field you need

Cannot access var object of inner class in kotlin

I am trying to write a RecyclerView adapter class in Kotlin for android. I am trying to use the traditional way of creating a custom viewer class, for custom objects, and use a click listener in that. While I am able to do rest of the things like access the variables of inner class and show the RecyclerView, what I have not been able to do is add click listener to the var objects of inner class.
ie something like
var convertView : View? = itemView
convertView.setOnClickListener(this)
Following is my complete code of adapter class
public open class TestAdapter(val items: MutableList<Any>, val context: Activity) : RecyclerView.Adapter<TestAdapter.CustomViewHolder>() {
public var mItem: MutableList<Any> = items
public var mActivity: Activity = context
protected var clickListener: ExampleInterface? = null
public interface ExampleInterface {
fun click(pos: Int) {
}
}
open public fun setListener(mInterFaceListener: ExampleInterface) {
clickListener = mInterFaceListener
}
override fun onCreateViewHolder(p0: ViewGroup, p1: Int): CustomViewHolder {
var parentLayout: View = LayoutInflater.from(mActivity).inflate(R.layout.custom_view, p0, false)
return CustomViewHolder(parentLayout)
// return CustomViewHolder(LayoutInflater.from(mActivity).inflate(R.layout.custom_view, p0, false))
}
override fun getItemCount(): Int {
return mItem.size
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onBindViewHolder(p0: CustomViewHolder, p1: Int) {
p0.dataView.text = mItem.get(p1).toString()
}
inner class CustomViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
var convertView: View? = itemView
var dataView: TextView = convertView!!.findViewById(R.id.data)
var mposition = adapterPosition
override fun onClick(p0: View?) {
if (clickListener != null) {
clickListener!!.click(mposition)
}
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
}
So if you see these two lines in CustomView class
var convertView: View? = itemView
var dataView: TextView = convertView!!.findViewById(R.id.data)
I cannot access these variables "convertView" and "dataView" so that I can set clicklistener to them. So how to achieve it ?
Thanks :)
I referred to this site
https://www.raywenderlich.com/367-android-recyclerview-tutorial-with-kotlin
Here I go to know my mistake , I need to use init in the class, there I am able to access it and initialize on click listener. Got it working
init {
convertView?.setOnClickListener(this)
}
Though the above answer could be acceptable as well, as I am new to Kotlin I cannot say which one is the better option, but my requirement is satisfied with the above mentioned site.
Thank you :)
In RecyclerView adapters, You could place the OnClickListeners in onCreateViewHolder in order to prevent them from being set each time onBindViewHolder is called (as onBindViewHolder is called multiple times when RecyclerView is scrolled). Use parentLayout in your onCreateViewHolder to access your views and set onClickListener to them. to determine current position in onCreateViewHolder you can do as below :
override fun onCreateViewHolder(p0: ViewGroup, p1: Int): CustomViewHolder {
val parentLayout: View = LayoutInflater.from(mActivity).inflate(R.layout.custom_view, p0, false)
val customViewHolder = CustomViewHolder(parentLayout)
parentLayout.myExampleTextView.setOnClickListener {
// Place onClick logic here.
// If you need position, do as bellow :
val adapterPosition = customViewHolder.adapterPosition
if(adapterPosition != RecyclerView.NO_POSITION) {
// Place your position dependent logic here
}
}
return customViewHolder
}
UPDATE:
I updated the code snippet above and added the RecyclerView.NO_POSITION (which is equal to -1) check. The reason for the position being returned as -1 is explained below.
From android docs:
The other set of position related methods are in the form of
AdapterPosition. (e.g. getAdapterPosition(), findViewHolderForAdapterPosition(int)) You should use these methods
when you need to work with up-to-date adapter positions even if they
may not have been reflected to layout yet. For example, if you want to
access the item in the adapter on a ViewHolder click, you should use
getAdapterPosition(). Beware that these methods may not be able to
calculate adapter positions if notifyDataSetChanged() has been called
and new layout has not yet been calculated. For this reasons, you
should carefully handle NO_POSITION or null results from these
methods.
you can access them in the onBindViewHolder using the p0 this way p0.dataView so there you can set listeners successfully

Categories

Resources