1

I am facing this problem while working at an Android app: I have a recycleview and every item has a delete button. I know I can add the button onclicklistener of every row item inside the onBindViewHolder in the adapter, but I want it specifically to be used from inside the MainActivity, not the adapter. Here is a brief sketch of my recycleview:

sketch

Here is the code for my adapter:

public class EntryAdapter extends RecyclerView.Adapter<EntryAdapter.MyViewHolder> {

    private Context context;
    private CRUD db;
    private List<Entry> entryList;

    public class MyViewHolder extends RecyclerView.ViewHolder {

        ImageView type;
        ImageView person;
        TextView amount;
        TextView amount_ron;
        ImageButton deleteB, editB, payB;
        TextView description;
        TextView timestamp;
        TextView positionTxt, noHolderPositionTxt;
        LinearLayout containter;
        Typeface SR, SB, SL;

        MyViewHolder(View view) {
            super(view);

            this.SB = Typeface.createFromAsset(context.getAssets(), "fonts/sansation_bold.ttf");
            this.SR = Typeface.createFromAsset(context.getAssets(), "fonts/sansation_regular.ttf");
            this.SL = Typeface.createFromAsset(context.getAssets(), "fonts/sansation_light.ttf");
            containter = view.findViewById(R.id.item_container);
            type = view.findViewById(R.id.debt_type);
            person = view.findViewById(R.id.debt_person);
            amount = view.findViewById(R.id.entry_cost);
            amount.setTypeface(SR);
            amount_ron = view.findViewById(R.id.entry_cost_ron);
            amount_ron.setTypeface(SR);
            deleteB = view.findViewById(R.id.delete_button);
            editB = view.findViewById(R.id.edit_button);
            payB = view.findViewById(R.id.pay_button);
            description = view.findViewById(R.id.descriptionTxt);
            description.setTypeface(SL);
            timestamp = view.findViewById(R.id.timestamp);
            timestamp.setTypeface(SR);
            positionTxt = view.findViewById(R.id.position);
            noHolderPositionTxt = view.findViewById(R.id.positionnotwithholder);

            db = new CRUD(context);
        }
    }

    public EntryAdapter(Context context, List<Entry> entryList) {
        this.context = context;
        this.entryList = entryList;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_entry, parent, false);
        return new MyViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(@NonNull final MyViewHolder holder, final int position) {

        Entry entry = entryList.get(holder.getAdapterPosition());
        holder.positionTxt.setText(String.valueOf(holder.getAdapterPosition()));
        holder.noHolderPositionTxt.setText(String.valueOf(position));

        switch(entry.getType()){
            case "FOOD": holder.type.setImageResource(R.drawable.food);
                break;
            case "FLOWERS": holder.type.setImageResource(R.drawable.flowers);
                break;
            case "GROCERIES": holder.type.setImageResource(R.drawable.groceries);
                break;
            case "HOLIDAY": holder.type.setImageResource(R.drawable.holiday);
                break;
            case "PHARMACY": holder.type.setImageResource(R.drawable.pharmacy);
                break;
            case "BILLS": holder.type.setImageResource(R.drawable.bills);
                break;
            case "CLOTHES": holder.type.setImageResource(R.drawable.clothes);
                break;
            case "TRANSPORT": holder.type.setImageResource(R.drawable.transport);
                break;
            case "ITEMS": holder.type.setImageResource(R.drawable.items);
                break;
            case "OTHERS": holder.type.setImageResource(R.drawable.others);
                break;
        }
        switch (entry.getPerson()){
            case "ew": holder.person.setImageResource(R.drawable.crisu_to_radu_small);
                break;
            case "wr": holder.person.setImageResource(R.drawable.radu_to_crisu_big);
                break;
        }
        switch (entry.getIsPaid()){
            case "YES": holder.containter.setAlpha((float) 0.3);
                        holder.payB.setVisibility(View.GONE);
                        holder.deleteB.setVisibility(View.GONE);
                        holder.editB.setVisibility(View.GONE);
                break;
            case "NO":  holder.containter.setAlpha((float) 1);
                        holder.payB.setVisibility(View.VISIBLE);
                        holder.deleteB.setVisibility(View.VISIBLE);
                        holder.editB.setVisibility(View.VISIBLE);
                break;
        }
        holder.amount.setText(entry.getAmount());
        holder.description.setText(entry.getDescription());
        holder.timestamp.setText(formatDate(entry.getTimestamp()));
//                deleteEntry(holder.getAdapterPosition());
    }

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

    private void deleteEntry(int position) {
        db.deleteEntry(entryList.get(position));
        entryList.remove(position);
        notifyItemRemoved(position);
        notifyDataSetChanged();
        notifyItemRangeChanged(position, entryList.size());
    }

    private String formatDate(String dateStr) {
        try {
            @SuppressLint("SimpleDateFormat") SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date = fmt.parse(dateStr);
            @SuppressLint("SimpleDateFormat") SimpleDateFormat fmtOut = new SimpleDateFormat("MMM d, HH:mm");
            return fmtOut.format(date);
        } catch (ParseException ignored) {}

        return "";
    }
}

Here is my MainActivity:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        fonts();


        recyclerView = findViewById(R.id.recycler_view);
        no_entry_message = findViewById(R.id.no_entry_message);
        no_entry_message.setTypeface(SL);
        title = findViewById(R.id.finance_title);
        title.setTypeface(SB);
        subtitle = findViewById(R.id.finance_subtitle);
        subtitle.setTypeface(SL);
        card_title = findViewById(R.id.total_title);
        card_title.setTypeface(SR);
        money_amount = findViewById(R.id.total_money);
        money_amount.setTypeface(SB);
        money_rom = findViewById(R.id.total_ron);
        money_rom.setTypeface(SB);
        total_calculation = findViewById(R.id.total_button);
        total_calculation.setTypeface(SR);
        total_container = findViewById(R.id.total_card_container);

        db = new CRUD(this);
        entryList.addAll(db.getAllEntries());

        fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                isUpdateDilog = false;
                addEntryDialog(null, -1);
            }
        });

        mAdapter = new EntryAdapter(this, entryList);
        RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
        recyclerView.setLayoutManager(mLayoutManager);
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        recyclerView.setAdapter(mAdapter);
        emptyList();
    }
//    private void deleteEntry(int position) {
//
//        db.deleteEntry(entryList.get(position));
//        entryList.remove(position);
//        mAdapter.notifyItemRemoved(position);
//        emptyList();
//    }

So basically, every time I click on the delete button inside the recyclerview item, I want the onclick event to happen in the MainActivity and use the method deleteEntry(position) so I can delete the specific item from my local sqlite database.

Also, if I want to put a condition in onBindViewHolder from my adapter, how can I change (for example) the color of a textview from MainActivity right there?

UPDATE - WITH H.sanati's ANSWER

Thanks again for the answer, H.sanati. Here is all I changed:

Created this Interface:

public interface OnClickListener {
    void onClick(int position, String button_pressed);
}

The integer position will store my item position inside the list and the string will tell which of my 3 buttons was pressed.

Then inside my Recyclview Adapter:

@Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_entry, parent, false);

        final MyViewHolder holder = new MyViewHolder(itemView);
        holder.deleteB.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ((MainActivity)context).onClick(holder.getAdapterPosition(), "DELETE_B");
            }
        });

        holder.editB.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ((MainActivity)context).onClick(holder.getAdapterPosition(), "EDIT_B");
            }
        });

        holder.payB.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ((MainActivity)context).onClick(holder.getAdapterPosition(), "PAY_B");
            }
        });

        return holder;
    }

Note that deleteB, editB and payB are all buttons that appear in every single list item. The string in the interface above tells which one of these was pressed.

Then in my MainActivity:

public class MainActivity extends AppCompatActivity implements OnClickListener {
@Override
    public void onClick(int item_position, String which_button_was_pressed) {
        switch (which_button_was_pressed)
        {
            case "DELETE_B":
                deleteEntry(item_position);
                Toast.makeText(this, "Delete button at position:" + item_position + "was pressed", Toast.LENGTH_SHORT).show();
                    break;
            case "EDIT_B":
                Toast.makeText(this, "Edit button at position:" + item_position + "was pressed", Toast.LENGTH_SHORT).show();
                break;
            case "PAY_B":
                Toast.makeText(this, "Pay button at position:" + item_position + "was pressed", Toast.LENGTH_SHORT).show();
                break;
        }

    }

Here there is a Toast massage to confirm the correct buttons were pressed and following, I'll be adding my methods for each case. Also I suggest that inside your methods in the MainActivity (let's say the the delete method, you can view it ballow) you should add the following lines marked with @@@ for an accurate list size and position update:

 private void deleteEntry(int position) {

            db.deleteEntry(entryList.get(position));
            entryList.remove(position);
      @@@   mAdapter.notifyItemRemoved(position);
      @@@   mAdapter.notifyDataSetChanged();
      @@@   mAdapter.notifyItemRangeChanged(position, entryList.size());
            emptyList();
        }

Hope this helps. Thanks!

RFM
  • 107
  • 7
  • 1
    Possible duplicate of [RecyclerView onClick](https://stackoverflow.com/questions/24471109/recyclerview-onclick) – Ivan Wooll Mar 03 '19 at 16:07

1 Answers1

1

at first, create an interface:

public interface OnClickListener {
    void onClick();
}

then implement this interface in your activity:

class MainActivity extends AppCompatActivity implements OnClickListener {
    @Override
    public void onClick() {
        //code
    }
}

do whatever you want in the onClick method after that call it in your recyclerview:

((MainActivity)context).onClick();

it's better to set your listeners in onCreateViewHolder to have a smooth scroll in recyclerview like this:

 @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.item_entry, parent, false);

        MyViewHolder holder = new MyViewHolder(view);

        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ((MainActivity)context).onClick();
            }
        });

        return holder;
    }
houman.sanati
  • 1,054
  • 3
  • 18
  • 34