Shlok Jain
Shlok Jain

Reputation: 51

IndexOutOfBoundsException in Adapter.onBindViewHolder in Android

My RecyclerView's Adapter seems to be crashing, I have visited a few questions but I cannot seem to understand what is going on. The questions I had visited mention that a list has been initialised again but I don't think I am initialising any list.

The link of the most relatable question: Link 1

Logcat

java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
        at java.util.ArrayList.get(ArrayList.java:437)
        at com.example.android.predictious.ui.market.voucher.VoucherAdapter.onBindViewHolder(VoucherAdapter.java:61)

VoucherAdapter.java

public class VoucherAdapter extends RecyclerView.Adapter<VoucherAdapter.VoucherViewHolder> {

    private final LayoutInflater mInflater;
    private final String TAG = "VoucherAdapter";
    private List<String> mTitle;

    public VoucherAdapter(Context context, List<String> mTitle) {
        this.mInflater = LayoutInflater.from(context);
        this.mTitle = mTitle;
        Log.d(TAG, "Constructor");
    }

    @NonNull
    @Override
    public VoucherAdapter.VoucherViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = mInflater.inflate(R.layout.voucher_card_view, parent, false);
        VoucherViewHolder viewHolder = new VoucherViewHolder(view);
        Log.d(TAG, "onCreateViewHolder");
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull VoucherAdapter.VoucherViewHolder holder, int position) {
        Log.d(TAG, "onBindViewHolder");

        String title = mTitle.get(position);
        holder.voucherTitle.setText(title);
    }

    @Override
    public int getItemCount() {
        return mTitle.size();
    }

    public void setTitle(List<String> Title) {
        this.mTitle = Title;
        notifyDataSetChanged();
    }

    public class VoucherViewHolder extends RecyclerView.ViewHolder {

        TextView voucherTitle;

        public VoucherViewHolder(@NonNull View itemView) {
            super(itemView);

            Log.d(TAG, "ViewHolder Class");

            voucherTitle = itemView.findViewById(R.id.voucherTitleText);
        }
    }
}

VoucherFragment.java

 mViewModel.getmTitleLiveData().observe(getViewLifecycleOwner(), new Observer<List<String>>() {
            @Override
            public void onChanged(List<String> titleList) {
                mTitle.addAll(titleList);
                adapter.setTitle(mTitle);
                Log.d(TAG, "Data sent to Adapter");
            }
        });

ViewModel.java

public MutableLiveData<List<String>> getmTitleLiveData() {
        repository
                .getVoucherCol()
                .whereEqualTo("category", categoryTitle)
                .addSnapshotListener(new EventListener<QuerySnapshot>() {
            @Override
            public void onEvent(@Nullable QuerySnapshot queryDocumentSnapshots, @Nullable FirebaseFirestoreException e) {
                if (e != null) {
                    mTitleLiveData = null;
                    Log.d(TAG, "Could not receive TITLE data \n " + e);
                    return;
                }
                List<String> titleList = new ArrayList<>();
                for (QueryDocumentSnapshot doc: queryDocumentSnapshots) {
                    if (doc.get("title") != null) {
                        titleList.add((String) doc.get("title"));
                    }
                }
                mTitleLiveData.postValue(titleList);
                Log.d(TAG, "Successfully retrieved TITLE data" + titleList);
            }
        });
        return mTitleLiveData;
    }

Upvotes: 0

Views: 742

Answers (1)

Alex Rmcf
Alex Rmcf

Reputation: 924

Here

@Override
    public void onBindViewHolder(@NonNull VoucherAdapter.VoucherViewHolder holder, int position) {
        Log.d(TAG, "onBindViewHolder");

        String title = mTitle.get(position);
        holder.voucherTitle.setText(title);
    }

yout mTitle is empty when you create your adapter, so that is way you get the exeption. You need to change it to this one:

if (mTitle.size()>0){
String title = mTitle.get(position);
            holder.voucherTitle.setText(title);
}

You suppose to add values to it not like you do here:

 public void setTitle(List<String> Title) {
        this.mTitle = Title;
        notifyDataSetChanged();
    }

I strongly recomend you to remove this setTitle method. Pass this list via your adapter constructor. If you need to change this list - change it in your VoucherFragment. You can do it two ways - the way you did with little changes:

mViewModel.getmTitleLiveData().observe(getViewLifecycleOwner(), new Observer<List<String>>() {
            @Override
            public void onChanged(List<String> titleList) {
                mTitle.addAll(titleList);
                adapter.notifyDataSetChanged;
                Log.d(TAG, "Data sent to Adapter");
            }
        });

or another way:

mViewModel.getmTitleLiveData().observe(getViewLifecycleOwner(), new Observer<List<String>>() {
            @Override
            public void onChanged(List<String> titleList) {
                yourRecyclerView.setAdapter(new VoucherAdapter(getContext, titleList))
                Log.d(TAG, "Data sent to Adapter");
            }

Hope that helps

Upvotes: 1

Related Questions