Android recyclerView findViewHolderForAdapterPosition returns null

后端 未结 6 1090
醉梦人生
醉梦人生 2020-11-27 07:08

I want to click an item in recyclerView programmatically, I found a way do that:

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


        
相关标签:
6条回答
  • 2020-11-27 07:53

    I wouldnt recommend using post delay. Although it works the timing is arbitrary.

    Using OnPreDrawListener on the recyclerview, timing will be aligned with the next draw cycle and visible items are accessible.

    0 讨论(0)
  • 2020-11-27 07:58

    Hey I've solved the problem this way:

    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. Added ArrayList mViewholders field inside class
    2. added each viewholder instance to mViewHolders arraylist inside onBindSwipeViewHolder method
    3. used mViewholders arraylist instead of findViewHolderForadapterposition method inside setTotalSum method
    0 讨论(0)
  • 2020-11-27 07:59

    you can do this:

       listView.postDelayed(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        if(listView.findViewHolderForAdapterPosition(0)!=null )
                        {
    
                            listView.findViewHolderForAdapterPosition(0).itemView.performClick();
                        }
                    }
                },50);
    
    0 讨论(0)
  • 2020-11-27 07:59

    you can do this:

    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);
                }
            }
        });
    }
    
    0 讨论(0)
  • 2020-11-27 08:01

    I know that is very late, but maybe is helpful for other people in the Kotlin era:

     binding.recycler.post {
         val view = binding.recycler.findViewHolderForAdapterPosition(position)?.itemView?.performClick()
     }
    
    0 讨论(0)
  • 2020-11-27 08:02

    According to the 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.

    It's not safe to use findViewHolderForAdapterPosition().

    While you call this method after listView.swapAdapter(listadapter, false); you'll always get a null as result because notifyDataSetChanged() will be called.

    0 讨论(0)
提交回复
热议问题