为什么我的RecyclerView.ViewHolder的onClick方法有时不被调用?
我的ViewHolder
实现了View.OnClickListener
,正如this answer中的建议。除此之外,我再次检查了我的适配器类与官方文档中的示例类似。为什么我的RecyclerView.ViewHolder的onClick方法有时不被调用?
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private View view;
public ViewHolder(View view) {
super(view);
view.setOnClickListener(this);
this.view = view;
}
public View getView() {
return view;
}
@Override
public void onClick(View view) {
Context context = view.getContext();
Intent intent = new Intent(context, DetailsActivity.class);
context.startActivity(intent);
}
}
但如果我测试我的应用程序我观察这个非常奇怪的现象:如果我攻上排在启动过程中看到,如预期执行onClick
方法。现在我向下滚动,使其他行可见。我点击某处并没有任何反应,第二次点击 - 如果它在同一行上 - 再次运行。如果我滚动回到顶部,则会发生同样的情况,我必须点击两次以获取我的onClick
方法。
任何想法为什么会发生这种情况?
编辑:的完整代码,现在设置听者onBindViewHolder
:
public class ComposersAdapter extends RecyclerView.Adapter<ComposersAdapter.ViewHolder> {
public static class ViewHolder extends RecyclerView.ViewHolder {
private View view;
public ViewHolder(View view) {
super(view);
this.view = view;
}
public View getView() {
return view;
}
}
private final String EXTRA_COMPOSER_ID = "composerId";
private List<Composer> composers;
public ComposersAdapter(List<Composer> composers) {
this.composers = composers;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.text_layout, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
View view = holder.getView();
TextView textView = view.findViewById(R.id.textView);
textView.setText(composers.get(position).getTitle());
holder.getView().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Context context = view.getContext();
Intent intent = new Intent(context, ComposerActivity.class);
intent.putExtra(EXTRA_COMPOSER_ID, holder.getAdapterPosition());
context.startActivity(intent);
}
});
}
@Override
public int getItemCount() {
return composers.size();
}
}
UPDATE:这个问题似乎被连接到RecyclerView驻留在我设置app:layout_scrollFlags="scroll|enterAlways"
活动的工具栏。如果我删除该问题不存在了。也许这与工具栏捕捉触摸事件有关?我没有足够的经验来检查我自己。
指定 onBindViewHolder(RecyclerView.ViewHolder holder, int position)
中的点击收听者。
onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// start some activity
}
});
}
在绑定视图持有者是何时一个视图持有者正确地绑定到适配器和视图的个别实例可在这里。
holder.itemView
将给你对viewHolder的视图实例的引用。 因此,您不需要在ViewHolder中使用getView()
类似的方法。
'holder.setOnClickListener'如何工作?从持有者处获得视图后,您可能是指'view.setOnClickListener',或者我误解了某些东西? –
是的,你是正确的@伊利亚斯!我在脑海里打字,对不起!我刚刚更新了答案。 – rgv
好吧,我更新了我的代码,但问题仍然存在。无论如何谢谢澄清! –
甲ViewHolder介绍有关其内的RecyclerView地方的项目视图和元数据。
RecyclerView.Adapter实现应该子类ViewHolder和添加字段用于高速缓存可能昂贵findViewById(int)的结果。
我在项目中有类似的问题,我做了一些示例,你可以看看可能有助于解决你的问题。
public class ProductAdapter extends RecyclerView.Adapter<ProductAdapter.ViewHolder> {
private List<Ad> adsList= new ArrayList<>();
private Context mContext;
static OnItemClickListener mItemClickListener;
//Provide a reference to the views for each data item
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
@BindView(R.id.mainHolder)
public RelativeLayout placeHolder;
@BindView(R.id.tv_ad_name)
public TextView tvAdName;
@BindView(R.id.tv_no_of_rating)
public TextView tvNoOfRating;
@BindView(R.id.tv_minOs)
public TextView tvMinOs;
@BindView(R.id.iv_product_thumbnail)
public ImageView ivPrductThumbnail;
public ViewHolder(View v) {
super(v);
ButterKnife.bind(this, v);
placeHolder.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (mItemClickListener != null) {
mItemClickListener.onItemClick(itemView, getPosition());
}
}
}
public interface OnItemClickListener {
void onItemClick(View view, int position);
}
public void setOnItemClickListener(final OnItemClickListener mItemClickListener) {
this.mItemClickListener = mItemClickListener;
}
//Provide a suitable constructor
public ProductAdapter(Context context){
mContext = context;
}
public void setAd(List<Ad> aList) {
adsList.clear();
adsList.addAll(aList);
notifyDataSetChanged();
}
//Create new views (invoked by the layout manager)
@Override
public ProductAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//Creating a new view
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.product_list_items,parent,false);
ViewHolder vh = new ViewHolder(v);
return vh;
}
//Replace the contents of a view (invoked by the layout manager
@Override
public void onBindViewHolder(ProductAdapter.ViewHolder holder, int position) {
// - replace the contents of the view with that element
Ad ad = adsList.get(position);
holder.tvAdName.setText(ad.getProductName());
holder.tvNoOfRating.setText(ad.getNumberOfRatings());
holder.tvMinOs.setText(ad.getMinOSVersion());
Glide.with(mContext)
.load(ad.getProductThumbnail())
.into(holder.ivPrductThumbnail);
}
@Override
public int getItemCount() {
return adsList.size();
}
}
编辑:你可能已在申报ViewHolder类中的TextView。
不幸的是,这也没有帮助。缓存视图不应该是必需的,因为设置文本按预期工作,并将实际的点击监听器放置在其他地方(如btw,你应该提到它在MainActivity.java中)不会改变任何内容。我有这种感觉,我在这里错过了一些基本的东西。 –
你可以请检查这个:https://github.com/dharmakshetri/Android-API-Demos/blob/master/app/src/main/java/co/apidemos/adapter/GitHubAdapter.java –
我不知道这会工作与否,但是你可以请尝试通过从这里删除'静态'公共静态类ViewHolder扩展RecyclerView.ViewHolder {}。 –
为什么不在onBindViewHolder中完成它?而不是在这里有一个点击监听器,试试在绑定方法的根视图上有一个 – Kushan
你是对的,这是更清洁。但问题依然存在。 –
对不起,我刚刚看到了Kushan的评论。 @Elias,请提供适配器的完整代码,我想你可能会错误地持有/分配视图引用。 – rgv