user3718908x100
user3718908x100

Reputation: 8509

OnClickListener Inside Adapter View

In my activity I am displaying a list of data, each row has an edit and delete button. The listeners for these buttons are defined inside the listviews adapter.

I have implemented a custom array adapter:

public class SalesArrayAdapter extends ArrayAdapter<SaleModel> {

    private Context context;
    private int altColour;
    private SaleModel sale;
    private int position;
    private ArrayList<SaleModel> sales;

    private static class ViewHolder{
        RelativeLayout container;
        TextView tvId;
        TextView tvDate;
        TextView tvBusNo;
        TextView tvDriver;
        TextView tvNoOfTrips;
        TextView tvTotalExpenditure;
        TextView tvTotal;
        TextView tvAmountReceived;
        TextView tvStatus;
        TextView tvReceiptCode;
        ImageButton btnEdit;
        ImageButton btnRemove;
    }

    public SalesArrayAdapter(@NonNull Context context, @NonNull ArrayList<SaleModel> sales) {
        super(context, R.layout.row_sales, sales);
        //this.getContext() = getContext();
        //this.sales = sales;
    }

    @NonNull
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    public View getView(final int position, View convertView, @NonNull ViewGroup parent) {
        // Get the data item for this position
        sale = getItem(position);

        // Check if an existing view is being reused, otherwise inflate the view
        ViewHolder viewHolder; // view lookup cache stored in tag
        if (convertView == null) {
            // If there's no view to re-use, inflate a brand new view for row
            viewHolder = new ViewHolder();
            LayoutInflater inflater = LayoutInflater.from(getContext());
            convertView = inflater.inflate(R.layout.row_sales, parent, false);
            viewHolder.container = (RelativeLayout) convertView.findViewById(R.id.row_sales_ll_container);
            viewHolder.tvId = (TextView) convertView.findViewById(R.id.row_sales_tv_id);
            viewHolder.tvDate = (TextView) convertView.findViewById(R.id.row_sales_tv_date);
            viewHolder.tvDriver = (TextView) convertView.findViewById(R.id.row_sales_tv_driver);
            viewHolder.tvNoOfTrips = (TextView) convertView.findViewById(R.id.row_sales_tv_total_no_of_trips);
            viewHolder.tvTotalExpenditure = (TextView) convertView.findViewById(R.id.row_sales_tv_total_expenditure);
            viewHolder.tvTotal = (TextView) convertView.findViewById(R.id.row_sales_tv_total);
            viewHolder.tvAmountReceived = (TextView) convertView.findViewById(R.id.row_sales_tv_amount_received);
            viewHolder.tvStatus = (TextView) convertView.findViewById(R.id.row_sales_tv_status);
            viewHolder.tvReceiptCode = (TextView) convertView.findViewById(R.id.row_sales_tv_receipt_code);
            viewHolder.btnEdit = (ImageButton) convertView.findViewById(R.id.row_sales_btn_edit);
            viewHolder.btnRemove = (ImageButton) convertView.findViewById(R.id.row_sales_btn_trash);

            // Cache the viewHolder object inside the fresh view
            convertView.setTag(viewHolder);
        } else {
            // View is being recycled, retrieve the viewHolder object from tag
            viewHolder = (ViewHolder) convertView.getTag();
        }
        // Populate the data from the data object via the viewHolder object
        // into the template view.

        if (altColour == 0) {
            viewHolder.container.setBackgroundColor(Color.parseColor("#FFFFFF"));
            altColour = 1;
        } else {
            viewHolder.container.setBackgroundColor(Color.parseColor("#EFEFEF"));
            altColour = 0;
        }

        viewHolder.tvId.setText(String.valueOf(sale.getId()));
        viewHolder.tvDate.setText(sale.getDate());
        viewHolder.tvDriver.setText(sale.getDriver());
        double totalTripsAmount = 0;
        for(int c = 0; c < sale.getTrips().length(); c++) {
            try {
                totalTripsAmount += sale.getTrips().getJSONObject(c).getDouble("trip_amount");
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        viewHolder.tvNoOfTrips.setText("GHS "+totalTripsAmount);
        double totalExpenditureAmount = 0;
        for(int c = 0; c < sale.getExpenditure().length(); c++) {
            try {
                totalExpenditureAmount += sale.getExpenditure().getJSONObject(c).getDouble("amount");
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        viewHolder.tvTotalExpenditure.setText("GHS "+totalExpenditureAmount);
        viewHolder.tvTotal.setText("GHS "+sale.getTotal());
        viewHolder.tvAmountReceived.setText("GHS "+sale.getAmountReceived());
        viewHolder.tvStatus.setText(sale.getIsPending() == 1 ? "Pending" : "Complete");
        viewHolder.tvReceiptCode.setText(sale.getReceiptCode());
        viewHolder.btnEdit.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent editSaleIntent = new Intent(getContext(), EditSaleActivity.class);
                editSaleIntent.putExtra("sale", sale.toJson().toString());
                ((Activity) getContext()).startActivityForResult(editSaleIntent, 800);
            }
        });

        viewHolder.btnRemove.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                int pos = new Integer(getPosition(sale));
                removeSale(pos);
            }

        });

        // Return the completed view to render on screen
        return convertView;
    }

    private void removeSale(final int position) {

        AlertDialog.Builder builder = new AlertDialog.Builder(getContext());

        builder.setTitle("Confirm");
        builder.setMessage("Are you sure you want to delete?");

        builder.setPositiveButton("YES", new DialogInterface.OnClickListener() {

            public void onClick(DialogInterface dialog, int which) {
                //Log.i("btnYes", "works");
                SalesRequest salesRequest = new SalesRequest(getContext());
                remove(getItem(position));
                notifyDataSetChanged();
                salesRequest.remove(getItem(position).getId(), mTrashOnSuccessListener, mTrashOnErrorListener);
            }

        });

        builder.setNegativeButton("NO", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                // Do nothing
                dialog.dismiss();
            }
        });
        AlertDialog alert = builder.create();
        alert.show();
    }

    private Response.Listener<JSONObject> mTrashOnSuccessListener = new Response.Listener<JSONObject>() {
        @Override
        public void onResponse(JSONObject response) {
            //
        }
    };

    Response.ErrorListener mTrashOnErrorListener = new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            Utils.showNetworkResponse(getContext(), error);
        }
    };

}

Now my issue is when I click the delete or edit button for any item being displayed it always picks the position or id of the last item being display in the listview.

For example if I wanted to delete the second item in the listview with a position of 1 it would pick the last item being displayed with a position of 10.

I've tried soo many things and made soo many changes but nothing has worked so far, this is my final code.

Upvotes: 1

Views: 1864

Answers (4)

Chaitanya Atkuri
Chaitanya Atkuri

Reputation: 1672

Try to set the tag for the buttons at each position in the following way, so that when ever a button is clicked you can get back the position using the tag.

@NonNull
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public View getView(final int position, View convertView, @NonNull ViewGroup parent) {
    // Get the data item for this position
    sale = getItem(position);

    // Check if an existing view is being reused, otherwise inflate the view
    ViewHolder viewHolder; // view lookup cache stored in tag
    if (convertView == null) {
        // If there's no view to re-use, inflate a brand new view for row
        viewHolder = new ViewHolder();
        LayoutInflater inflater = LayoutInflater.from(getContext());
        convertView = inflater.inflate(R.layout.row_sales, parent, false);
        //Fetch other views here .....

        viewHolder.btnEdit = (ImageButton) convertView.findViewById(R.id.row_sales_btn_edit);
        viewHolder.btnRemove = (ImageButton) convertView.findViewById(R.id.row_sales_btn_trash);

        // Cache the viewHolder object inside the fresh view
        convertView.setTag(viewHolder);
    } else {
        // View is being recycled, retrieve the viewHolder object from tag
        viewHolder = (ViewHolder) convertView.getTag();
    }

    //Setting the position as the tag for both buttons
    viewHolder.btnRemove.setTag(position);
    viewHolder.btnEdit.setTag(position);

Now in click listener..

viewHolder.btnRemove.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                //Remove the below line
                int pos = new Integer(getPosition(sale));
                //Use this
                int pos = (int)v.getTag();
                removeSale(pos);
            }

    });

Hope, am helpful.

Upvotes: 1

Ways Test
Ways Test

Reputation: 12

  holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (fileDataVo.isPdf()) {
                    Intent intent = new Intent(context, PdfActivity.class);
                    intent.putExtra("position", position);
                    context.startActivity(intent);
                } else if (fileDataVo.isExcel()) {
                    Intent intent = new Intent(context, ExcelFileActivity.class);
                    intent.putExtra("position", position);
                    context.startActivity(intent);
                }
                else if (fileDataVo.isPpt()) {
                    Intent intent = new Intent(context, PptActivity.class);
                    intent.putExtra("position", position);
                    context.startActivity(intent);
                }
            }

Upvotes: 0

Pulak
Pulak

Reputation: 768

Set the position of each ViewHolder object as a tag to the buttons and retrieve it using getTag() when they are clicked. Something like this needs to be done: viewHolder.btnEdit.setTag(position)

And inside onClick(), retrieve the position as viewHolder.btnEdit.getTag()

For using the viewHolder object inside onClick(), it must be declared final so you can copy the object as final ViewHolder finalHolder = viewHolder and do the above with finalHolder object

Upvotes: 1

Abdul Waheed
Abdul Waheed

Reputation: 4678

You can add a tag in a button. Tag the current position to the button when getView method is called every time. When the button is clicked get the tage of the button and it will return the updated value/position of the button. And do what you want to do with that current position in call back of that button click. Hope that helps Adding more information you have this line of code

 viewHolder.btnEdit 

this is the edit button . Now you should add a tag to this button using below code. You need to use below code after else clause of Viewholder object initialization.

viewHolder.btnEdit.setTag(position);

And in call back of onclick use below code

button.getTag()

Upvotes: 1

Related Questions