为什么有时不调用我的RecyclerView.ViewHolder的onClick方法?

时间:2017-12-27 19:47:55

标签: java android

我的ViewHolder按照this answer中的建议实施View.OnClickListener。除此之外,我仔细检查了我的适配器类与官方文档中的示例类似。

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();
    }
}

更新:此问题似乎与RecyclerView所在活动的工具栏相关联。我已设置app:layout_scrollFlags="scroll|enterAlways",如果我删除该问题,则不再存在。也许这与捕获触摸事件的工具栏有关?我没有足够的经验来检验自己。

2 个答案:

答案 0 :(得分:1)

分配点击监听器 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
             }
});
}

On Bind View Holder是指视图符号正确绑定到适配器,并且此处提供了视图的各个实例。

holder.itemView 

将为您提供viewHolder视图实例的参考。 因此,您不必在ViewHolder中getView()使用CREATE TABLE #data ( [Time] datetime, [EQID] nvarchar(10), [Status] bit, [User] nvarchar(10) ) INSERT INTO #data VALUES ('2017-12-27 12:12am', 'EQ1', 0, 'SA') INSERT INTO #data VALUES ('2017-12-27 12:14am', 'EQ1', 1, 'SA') INSERT INTO #data VALUES ('2017-12-27 02:30am', 'EQ1', 0, 'SA') INSERT INTO #data VALUES ('2017-12-27 03:30am', 'EQ1', 1, 'SA') INSERT INTO #data VALUES ('2017-12-27 05:30am', 'EQ1', 0, 'SA') INSERT INTO #data VALUES ('2017-12-27 06:30am', 'EQ1', 1, 'SA') -- Get the next time where status is 1 SELECT D1.[Time] as 'In_Time' , D2.[Time] as 'Out_Time' , D1.[EQID] , D1.[User] FROM #data D1 LEFT JOIN #data D2 ON D2.[Time] = (SELECT TOP 1 [Time] FROM #data WHERE [Status] = 1 AND [Time] > D1.[Time] AND [User] = D1.[User] AND [EQID] = D1.[EQID] ORDER BY [Time]) WHERE D1.[Status] = 0 方法。

答案 1 :(得分:0)

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();
    }
}

完整可行的代码链接here。和 link2

修改:您可能需要在 ViewHolder 类中声明 textview