Android recyclerView findViewHolderForAdapterPosition returns 空

Android recyclerView findViewHolderForAdapterPosition returns null

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

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

但这对我不起作用,findViewHolderForAdapterPosition 只是 returns null。

我的代码中是否遗漏了什么?

历史列表适配器:

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

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

根据official documentation

if notifyDataSetChanged() has been called but the new layout has not been calculated yet, this method will return null since the new positions of views are unknown until the layout is calculated.

使用 findViewHolderForAdapterPosition() 不安全。

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

嘿,我是这样解决问题的:

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. 在 class
  2. 中添加了 ArrayList mViewholders 字段
  3. 将每个 viewholder 实例添加到 onBindSwipeViewHolder 方法内的 mViewHolders arraylist
  4. 在 setTotalSum 方法中使用 mViewholders arraylist 而不是 findViewHolderForadapterposition 方法

你可以这样做:

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

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

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

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

你可以这样做:

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

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

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

你应该使用 recyclerview.findViewHolderForLayoutPosition(position)