问题
I looked at many solutions posted online but they couldn't solve my problem. Probably the adapter position is returning -1 but why?
java.lang.ArrayIndexOutOfBoundsException: length=10; index=-1
at java.util.ArrayList.get(ArrayList.java:439)
at
com.firebase.ui.common.BaseObservableSnapshotArray.getSnapshot(BaseObservableSnapshotArray.java:70)
at com.example.twitterclone.adapters.MyAdapter$TweetViewHolder.<init>(MyAdapter.kt:36)
at com.example.twitterclone.adapters.MyAdapter.onCreateViewHolder(MyAdapter.kt:50)
at com.example.twitterclone.adapters.MyAdapter.onCreateViewHolder(MyAdapter.kt:21)
at androidx.recyclerview.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:7078)
at
RecyclerViewAdapterCode:
class MyAdapter(
options: FirestoreRecyclerOptions<Tweet>,
private val clickInterface: ClickInterface
):FirestoreRecyclerAdapter<Tweet, MyAdapter.TweetViewHolder>(options) {
inner class TweetViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val profile =
view.findViewById<de.hdodenhof.circleimageview.CircleImageView>(R.id.userProfile)
val tweet = view.findViewById<TextView>(R.id.tweet)
val like = view.findViewById<TextView>(R.id.totalLikes)
val thumbsUp = view.findViewById<ImageView>(R.id.thumbsUp)
val name=view.findViewById<TextView>(R.id.tweetUserName)
init {
val tweetId=snapshots.getSnapshot(adapterPosition).get("tweetId")
thumbsUp.setOnClickListener {
clickInterface.clickLike(tweetId.toString())
}
}
}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): TweetViewHolder {
val viewHolder = TweetViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.post_tweets_item, parent, false)
)
return viewHolder
}
override fun onBindViewHolder(
holder: TweetViewHolder,
position: Int,
model: Tweet
) {
holder.tweet.text = model.content.toString()
holder.like.text = model.likes.toString()
UserDao().getUser(model.uid!!).get().addOnSuccessListener {
holder.name.text = it.get("name").toString()
Glide.with(holder.profile.context).load(it.get("profileUrl").toString())
.into(holder.profile)
}
}
}
LayoutCode
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_margin="10dp"
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="2dp"
app:cardCornerRadius="5dp"
app:cardElevation="2dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/userProfile"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginTop="8dp"
android:layout_marginLeft="8dp" />
<TextView
android:id="@+id/tweetUserName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:textColor="@android:color/black"
android:layout_marginTop="8dp" />
</LinearLayout>
<TextView
android:id="@+id/tweet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="13dp"
android:textColor="@android:color/black" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="80dp"
android:orientation="vertical"
android:padding="8dp">
<ImageView
android:layout_width="30dp"
android:id="@+id/thumbsUp"
android:clickable="true"
android:layout_height="30dp"
android:src="@drawable/ic_baseline_thumb_up_24" />
<TextView
android:id="@+id/totalLikes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="80dp"
android:orientation="vertical"
android:padding="8dp">
<ImageView
android:clickable="true"
android:layout_width="30dp"
android:layout_height="30dp"
android:id="@+id/comments"
android:src="@drawable/ic_baseline_comment_24" />
<TextView
android:id="@+id/totalComments"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
回答1:
adapterPosition
in the ViewHolder's init block is returning -1. So we just need to call adapterPosition
in the listener which will solve the issue, since it would retrieve the position when the view holder is created and attached to the recyclerview
. Setting any kind of listeners in the init block is a good approach since the onCreateViewHolder
called only once to create a view holder but the onBindViewHolder
called multiple times for the same view holder, so setting listeners in the onBindViewHolder
would be redundant.
init {
thumbsUp.setOnClickListener {
val tweetId=snapshots.getSnapshot(adapterPosition).get("tweetId")
clickInterface.clickLike(tweetId.toString())
}
}
回答2:
Attache you onClickListener in onBindViewHolder
override fun onBindViewHolder(
holder: TweetViewHolder,
position: Int,
model: Tweet
) {
//your code of attaching data to view
holder.thumbsUp.setOnClickListener{
clickInterface.clickLike(model.tweetId.toString())
}
}
Reconsider your application architecture. As asking DAO for data inside RecyclerView.Adapter is quite strange approach
回答3:
Yeah, I'd expect adapterPosition
in your getSnapshot
call in the ViewHolder
's init block is returning -1. As far as I'm aware, all the adapter position getters return the position of the last requested item for display. But when you're first creating ViewHolder
s, nothing has bound to the adapter yet (it's all still in the setup phase), so its default position
is probably -1.
Basically the way RecyclerView
s work is this - you define these ViewHolder
objects which are basically things that display data for each item. Instead of having one for each item in the list, the adapter creates a handful of them (enough to fill the visible area and a couple either side), and then recycles them by moving them around when they're out of view, and updates their contents to represent a different item.
onCreateViewHolder
is what the adapter calls to create those container objects. It's where you inflate the layout and usually do findViewById
on the views so you have a reference to them, and you can just set a TextView
's text instead of having to fnd the view every time you want to update it.
onBindViewHolder
is what gets called when you need to update a ViewHolder
with a different item's info. This is where you actually do all the setting of data, changing images and whatever, updating click listeners if necessary.
Basically you shouldn't be using adapterPosition
in your ViewHolder
's init
block, because that gets called once, when the object is constructed. Not only do you not have a meaningful position at that point, but isn't that something you'll want to update often, as the position changes? That's what onBindViewHolder
is for! It has the position passed in and everything. That's the method where you set state
来源:https://stackoverflow.com/questions/65521667/onclicklistener-is-not-working-inside-my-adapter-class