Issue
When I add an item by button Scan Now, the public double sumCost
value incrementes by the cost
value in the AddItem
method and then TextView(android:id="@+id/SumText"
) assigns this value. And How to decrease sumCost
by the number that is in cost
and set new text in TextView when pressing the Delete
button? Thanks for any help
enter image description here
My full code:
MainActivity:
package com.example.testfirst;
...
public class MainActivity extends AppCompatActivity {
TextView sumText;
Button buttonAdd;
List<Contact> contacts = new LinkedList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_users);
buttonAdd = (Button) findViewById(R.id.scanBtn);
sumText = (TextView) findViewById(R.id.SumText);
buttonAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AddItem("Tom", 2.45);
sumText.setText(Double.toString(sumCost));
}
});
}
public void AddItem(String name, double cost){
sumCost += cost;
RecyclerView rvContacts = (RecyclerView) findViewById(R.id.recyclerView);
ContactsAdapter adapter = new ContactsAdapter(contacts);
rvContacts.setAdapter(adapter);
rvContacts.setLayoutManager(new LinearLayoutManager(this));
contacts.add(new Contact(name,Double.toString(cost)));
}
public double sumCost = 0;
}
Contact(Model class):
...
public class Contact {
private String mName;
private String mCost;
public Contact(String name, String cost) {
mName = name;
mCost = cost;
}
public String getName() {
return mName;
}
public String getCost() {
return mCost;
}
}
ContactsAdapter:
...
public class ContactsAdapter extends RecyclerView.Adapter<ViewHolder>{
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View contactView = inflater.inflate(R.layout.item_contact, parent, false);
return new ViewHolder(contactView).linkAdapter(this);
}
///////////////
@NonNull
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Contact contact = mContacts.get(position);
TextView textViewId = holder.nameId;
textViewId.setText(contact.getName());
TextView textViewCost = holder.nameCost;
textViewCost.setText(contact.getCost());
}
@Override
public int getItemCount() {
return mContacts.size();
}
List<Contact> mContacts;
public ContactsAdapter(List<Contact> contacts) {
mContacts = contacts;
}
}
class ViewHolder extends RecyclerView.ViewHolder {
private ContactsAdapter adapter;
public TextView nameId;
public TextView nameCost;
public ViewHolder(@NonNull View itemView) {
super(itemView);
nameId = (TextView) itemView.findViewById(R.id.text);
nameCost = (TextView) itemView.findViewById(R.id.textCost);
itemView.findViewById(R.id.delete).setOnClickListener(view -> {
adapter.mContacts.remove(getAdapterPosition());
adapter.notifyItemRemoved(getAdapterPosition());
});
}
public ViewHolder linkAdapter(ContactsAdapter adapter){
this.adapter = adapter;
return this;
}
}
item_contact.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_margin="10dp"
app:cardCornerRadius="10dp"
app:cardElevation="5dp"
app:contentPadding="5dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:text="@string/app_name"
android:textSize="20sp" />
<TextView
android:id="@+id/textCost"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/text"
android:text="@string/app_name"
android:textSize="20sp" />
<Button
android:id="@+id/delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_marginTop="3dp"
android:layout_marginEnd="3dp"
android:text="Delete" />
</RelativeLayout>
</androidx.cardview.widget.CardView>
activity_users.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:id="@+id/SumText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="0.00"
android:textSize="30sp"/>
<Button
android:id="@+id/scanBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Scan now"
android:textSize="30sp"
android:layout_gravity="center_horizontal"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Solution
One easy way to do that would be do add a "Decrementer" interface in the adapter that it can call to decrement the total cost, like this:
// Define the interface
public interface Decrementer {
void onDelete(double cost);
}
// Define an instance of the interface to hold
private final Decrementer mDecrementer;
// Pass in a decrementer at construction
public ContactsAdapter(List<Contact> contacts, Decrementer decr) {
mContacts = contacts;
mDecrementer = decr;
}
@NonNull
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
// get views and such ...
// Call the decrementer method when the button is clicked
// Could set this in onBindViewHolder, or pass the decrementer
// into the ViewHolder itself and use it there.
deleteButton.setOnClickListener(view -> {
int pos = holder.getAdapterPosition();
Contact c = mContacts.get(pos);
// add getCostAmount to return a double, or better yet, just
// store it as a Double instead of a string in Contact
mDecrementer.onDelete(c.getCostAmount());
mContacts.remove(pos);
notifyItemRemoved(pos);
});
}
and you would define the Decrementer when you create the adapter so it can access the Activity class members, like this:
ContactsAdapter adapter = new ContactsAdapter(contacts, new ContactsAdapter.Decrementer() {
@Override
public void onDelete(double cost) {
sumCost -= cost;
// change activity TextViews and such here too
sumText.setText(Double.toString(sumCost));
}
});
Side note: you don't need to create a whole new adapter every time you add an item, just add it to the contacts
array and call an appropriate notifyDataSetChanged
method on the existing adapter.
private ContactsAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_users);
//...
RecyclerView rvContacts = (RecyclerView) findViewById(R.id.recyclerView);
ContactsAdapter adapter = new ContactsAdapter(contacts);
rvContacts.setAdapter(adapter);
rvContacts.setLayoutManager(new LinearLayoutManager(this));
}
public void AddItem(String name, double cost){
sumCost += cost;
contacts.add(new Contact(name,Double.toString(cost)));
adapter.notifyDataSetChanged(); // or a less expensive notify call
}
Answered By - Tyler V
Answer Checked By - Candace Johnson (JavaFixing Volunteer)