【问题标题】:(android) Does getAdapterPosition() only work inside OnClick()?(android) getAdapterPosition() 是否只能在 OnClick() 中工作?
【发布时间】:2020-12-27 11:19:34
【问题描述】:

因为getAdapterPosition(),我现在很困惑。

我之所以问这个是因为getAdapterPosition()根据呼叫位置工作。

它适用于Anonymous Obect's OnClick()。但是如果它存在Anonymous Obect's Field,它就不起作用了。

此时的值为-1

有什么问题?

这是代码

Adapter.java (RecyclerView Adpater)

part.setOnClickListener(new View.OnClickListener() {
                int position = getAdapterPosition(); // didn't work
                @Override
                public void onClick(View v) {
                    int position = getAdapterPosition(); // work well
                    if(select == false) {
                        part.setBackgroundColor(context.getResources().getColor(R.color.teal_700));;
                        select = true;
                    }
                    else {
                        part.setBackgroundColor(context.getResources().getColor(R.color.white));;
                        select = false;
                    }
                    listener.OnItemClick(v, position); // or OnItemClick(v, getAdapterPosition()) works well, too
                }
            });

DialogFragment.java(错误位置)

dialogAdapter.setOnItemClickListener(new DialogItemAdapter.OnDialogItemClickListener() {
            @Override
            public void OnItemClick(View itemView, int pos) {
                Log.d(TAG, "OnItemClick: ");
                String data = dialogAdapter.getItem(pos).getPart(); // ERROR

            }
        });

这是Java的语法问题吗?

请帮帮我。

谢谢

【问题讨论】:

    标签: android android-recyclerview android-adapter


    【解决方案1】:

    原因在源代码的注释文档中已经提到。

    • 请注意,如果您调用了 {@link RecyclerView.Adapter#notifyDataSetChanged()},直到 * 下一个布局传递,此方法的返回值为 {@link #NO_POSITION}。

    这意味着如果 Adapter 仍处于充气状态,则 getAdapterPosition 将返回 -1 。如果您阅读了 cmets,它用于计算 ViewHolder 的位置以对用户 UI 操作(单击、触摸等)做出反应。

    您对匿名类所做的事情是使用getAdapterPosition() 设置了一个全局属性,该属性将在初始化时设置。有时可能是 -1,具体取决于适配器状态。

    如果你使用notifyItemRemoved() 也会给你带来麻烦,因为它不会为其他位置更新已保存的属性。假设您在适配器中有 0..10 个项目,并且您在删除 0 后调用 notifyItemRemoved(0),您的匿名属性仍将持有 1..10,因为他们没有收到通知,最终将在 ArrayIndexOutOfBound 。这就是为什么您应该使用getAdapterPosition() 来计算动作时的位置。

    为了安全起见,请始终检查NO_POSTION

    part.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = getAdapterPosition();
                if (position != RecyclerView.NO_POSITION) {
                    if (select == false) {
                        part.setBackgroundColor(context.getResources().getColor(R.color.teal_700));
                        select = true;
                    } else {
                        part.setBackgroundColor(context.getResources().getColor(R.color.white));
                        select = false;
                    }
                    listener.OnItemClick(v, position);
                }
            }
        });
    

    【讨论】:

    • 感谢您的详细解释!
    【解决方案2】:

    来自文档:

    /**
    * ...
    * @return The adapter position of the item if it still exists in the adapter.
    * {@link RecyclerView#NO_POSITION} if item has been removed from the adapter,
    * {@link RecyclerView.Adapter#notifyDataSetChanged()} has been called after the last
    * layout pass or the ViewHolder has already been recycled.
    */
    

    所以这意味着// did not work 行在从适配器中移除或 ViewHolder 被回收时被调用。换句话说,您的 ViewHolder 当前未显示在您的回收站视图中。

    // work well 行被调用时,ViewHolder 实际上在回收站视图中处于活动状态。

    我怀疑您在 ViewHolder 的构造函数中设置了侦听器,并且当构造函数运行时,viewholder 尚未在回收器视图中。如果你在onBindViewHolder 中设置你的点击监听器,我认为它应该可以工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多