【问题标题】:Android recyclerView findViewHolderForAdapterPosition returns nullAndroid recyclerView findViewHolderForAdapterPosition 返回 null
【发布时间】:2015-09-29 06:11:16
【问题描述】:

我想以编程方式单击 recyclerView 中的一个项目,我发现 a way 这样做:

recyclerView.findViewHolderForAdapterPosition(0).itemView.performClick();

但这对我不起作用,findViewHolderForAdapterPosition 只返回 null。

我是否遗漏了代码中的某些内容?

HistoryListAdapter:

public class HistoryListAdapter extends RecyclerView.Adapter<HistoryListAdapter.ViewHolder> {
private static ArrayList<RecordItem> recordItems;
private static FragmentActivity activity;
private static RecordList recordList;

public HistoryListAdapter(ArrayList<RecordItem> recordItems, FragmentActivity FA, RecordList FRL) {
    this.recordItems = recordItems;
    this.activity = FA;
    this.recordList = FRL;
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    // create a new view
    View itemLayoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.recorditem, parent, false);
    return new ViewHolder(itemLayoutView);
}

@Override
public void onBindViewHolder(final ViewHolder viewHolder, final int position) {
    // TextView setText ...
}

// Return the size of the itemsData (invoked by the layout manager)
@Override
public int getItemCount() {
    return recordItems.size();
}

// inner class to hold a reference to each item of RecyclerView
public static class ViewHolder extends RecyclerView.ViewHolder{
    public TextView result, datetime;

    public ViewHolder(View itemLayoutView) {
        super(itemLayoutView);
        itemLayoutView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (activity != null) {
                    // do something...
                }
            }
        });
        result = (TextView) itemLayoutView.findViewById(R.id.result);
        heartrate = (TextView) itemLayoutView.findViewById(R.id.heartrate);
        datetime = (TextView) itemLayoutView.findViewById(R.id.datetime);
    }
}
}

记录列表:

RecyclerView listView = (RecyclerView) layoutView.findViewById(R.id.listView);
HistoryListAdapter listadapter = new HistoryListAdapter(itemsToShow, getActivity(), RecordList.this);
listView.swapAdapter(listadapter, false);
listView.findViewHolderForAdapterPosition(0).itemView.performClick();

我省略了一些代码,但应该不会影响我代码的整体结构。

【问题讨论】:

标签: android android-recyclerview


【解决方案1】:

根据official documentation

如果 notifyDataSetChanged() 已被调用但新布局 没有 尚未计算,此方法将返回 null,因为新的 在计算布局之前,视图的位置是未知的。

使用findViewHolderForAdapterPosition() 不安全。

当您在 listView.swapAdapter(listadapter, false); 之后调用此方法时,您将始终得到 null 作为结果,因为将调用 notifyDataSetChanged()

【讨论】:

  • @J.K.这取决于您的需求。在这种情况下,即使 ViewTreeObserver 也不能保证在 ListView 生命周期内保持有效。
  • 那该用什么? @Rami
  • @eric 在适配器外部管理 viewHolder 是一种不好的做法。
  • 而你没有给出任何答案来解决这个问题,为什么?你刚才说它不会起作用......好吧......我们都已经发现了
  • recyclerView.post() 方法可以在 notifyDataSetChanged 之后使用。
【解决方案2】:

你可以这样做:

   listView.postDelayed(new Runnable()
            {
                @Override
                public void run()
                {
                    if(listView.findViewHolderForAdapterPosition(0)!=null )
                    {

                        listView.findViewHolderForAdapterPosition(0).itemView.performClick();
                    }
                }
            },50);

【讨论】:

  • 谢谢@Dharmaraj。像魅力一样工作。 stackoverflow.com/a/30883242 根据 yigit cmets 发生这种情况是因为位置没有布置好(例如,越界或被移除)。
  • 永远不要这样做。你确定 50 毫秒对于旧的和慢速的设备就足够了吗?每当你在那里看到postDelayed 时忽略答案(这不仅仅是关于这个问题,我已经看到很多类似的答案和其他问题的答案)。这是愚蠢的......
【解决方案3】:

我知道这已经很晚了,但也许对 Kotlin 时代的其他人有帮助:

 binding.recycler.post {
     val view = binding.recycler.findViewHolderForAdapterPosition(position)?.itemView?.performClick()
 }

【讨论】:

    【解决方案4】:

    你可以这样做:

    postAndNotifyAdapter(new Handler(),mRecyclerView);
    
    
    
    protected void postAndNotifyAdapter(final Handler handler, final RecyclerView recyclerView) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                if ( recyclerView.findViewHolderForLayoutPosition(0)!=null) {
                    // This will call first item by calling "performClick()" of view.
                    recyclerView.findViewHolderForLayoutPosition(0).itemView.performClick();
                } else {
                    //   
                    postAndNotifyAdapter(handler, recyclerView);
                }
            }
        });
    }
    

    【讨论】:

      【解决方案5】:

      嘿,我已经这样解决了这个问题:

      public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
      
      private TextView mTotalSum;
      protected int mSum;
      protected ArrayList<BasketRVAdapter.ViewHolder> mViewHolders;
      
      public BasketRVAdapter(JSONArray recyclerItems, Context context, TextView totalSum) {
          super(recyclerItems, context);
          mTotalSum = totalSum;
          mViewHolders = new ArrayList<>();
      }
      
      @Override
      public RecyclerView.ViewHolder onCreateSwipeViewHolder(ViewGroup parent, int i) {
          View view = LayoutInflater.from(parent.getContext())
                  .inflate(R.layout.view_basket_rv_item, parent, true);
      
          return new ViewHolder(view);
      }
      
      @Override
      public void onBindSwipeViewHolder(final RecyclerView.ViewHolder viewHolder, int position) {
          final BasketRVAdapter.ViewHolder holder = (BasketRVAdapter.ViewHolder) viewHolder;
      
          JSONObject object;
          try {
              object = mRecyclerItems.getJSONObject(position);
              final int priceValue = object.getInt("price");
              final int quantityValue = object.getInt("quantity");
      
              holder.setId(object.getInt("id"));
              holder.title.setText(object.getString("title"));
              holder.price.setText(String.format(mContext.getString(R.string.price), priceValue));
              holder.quantity.setText(String.valueOf(quantityValue));
              holder.sum.setText(String.valueOf(priceValue * quantityValue));
      
              holder.quantity.addTextChangedListener(new TextWatcher() {
                  @Override
                  public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
      
                  }
      
                  @Override
                  public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
      
                  }
      
                  @Override
                  public void afterTextChanged(Editable editable) {
                      String value = holder.quantity.getText().toString();
      
                      if (value.equals("")) {
                          return;
                      }
      
                      if (value.equals("0")) {
                          Toast.makeText(mContext, R.string.null_value_error, Toast.LENGTH_SHORT).show();
                          return;
                      }
                      holder.sum.setText(String.valueOf(priceValue * Integer.valueOf(value)));
                      setTotalSum();
                  }
      
              });
      
              mViewHolders.add(holder);
              mSum += priceValue * quantityValue;
      
              if (position == getItemCount() - 1) {
                  mTotalSum.setText(String.format(mContext.getString(R.string.total_sum), mSum));
              }
          } catch (JSONException e) {
              e.printStackTrace();
          }
      }
      
      @Override
      public SwipeConfiguration onCreateSwipeConfiguration(Context context, int i) {
          return new SwipeConfiguration.Builder(context)
                                       .setLeftSwipeBehaviour(SwipeConfiguration.SwipeBehaviour.NORMAL_SWIPE)
                                       .setRightSwipeBehaviour(SwipeConfiguration.SwipeBehaviour.NO_SWIPE)
                                       .setLeftBackgroundColorResource(R.color.dt_basket_deleted)
                                       .setLeftUndoDescription(R.string.deleted)
                                       .setDescriptionTextColorResource(R.color.dt_white)
                                       .setLeftUndoable(true)
                                       .build();
      }
      
      @Override
      public void onSwipe(int i, int i1, RecyclerView.ViewHolder holder) {
          try {
              if (i1 == SWIPE_LEFT) {
                  remove(i);
                  notifyItemRemoved(i);
                  mViewHolders.remove(i);
                  setTotalSum();
              }
          } catch (JSONException e) {
              e.printStackTrace();
          }
      }
      
      public int getSum() {
          return mSum;
      }
      
      public void setTotalSum() {
          int totalSum = 0;
      
          for (BasketRVAdapter.ViewHolder holder : mViewHolders) {
              totalSum += Integer.valueOf(holder.sum.getText().toString());
          }
      
          mSum = totalSum;
          mTotalSum.setText(String.format(mContext.getString(R.string.total_sum), totalSum));
      }
      
      public static class ViewHolder extends RecyclerView.ViewHolder {
      
          @Bind(R.id.trade_title)
          public TextView title;
          @Bind(R.id.trade_price)
          public TextView price;
          @Bind(R.id.trade_quantity)
          public EditText quantity;
          @Bind(R.id.sum)
          public TextView sum;
      
          private int mId;
      
          public ViewHolder(View itemView) {
              super(itemView);
              ButterKnife.bind(this, itemView);
          }
      
          public int getId() {
              return mId;
          }
      
          public void setId(int id) {
              mId = id;
          }
      }}
      
      1. 在类中添加了 ArrayList mViewholders 字段
      2. 在 onBindSwipeViewHolder 方法中将每个 viewholder 实例添加到 mViewHolders 数组列表中
      3. 在 setTotalSum 方法中使用 mViewholders arraylist 而不是 findViewHolderForadapterposition 方法

      【讨论】:

        【解决方案6】:

        我不建议使用后期延迟。虽然它有效,但时间是任意的。

        在 recyclerview 上使用 OnPreDrawListener,时间将与下一个绘制周期对齐,并且可见项目是可访问的。

        【讨论】:

          【解决方案7】:

          你应该使用recyclerview.findViewHolderForLayoutPosition(position)

          【讨论】:

          • 这与最受好评的答案提出的方法相同
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-10-31
          • 2012-06-22
          • 2012-05-28
          相关资源
          最近更新 更多