Это результат RecyclerView:

Схема базы данных Firestore:

это код, который я использую. Это только извлекает данные, как на изображении
db.collection("Expenses")
.whereEqualTo("Email",email)
.whereGreaterThanOrEqualTo("Date",MonthFirstDate)
.whereLessThanOrEqualTo("Date",TodayDate)
.orderBy("Date")
.get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
if (!queryDocumentSnapshots.isEmpty()){
expensesArrayList.clear();
List<DocumentSnapshot> list = queryDocumentSnapshots.getDocuments();
for (DocumentSnapshot ds : list){
expenses expenses = ds.toObject(expenses.class);
expensesArrayList.add(expenses);
}
adapter.notifyDataSetChanged();
}
}
})
Код адаптера recyclerview
import java.util.ArrayList;
public class expensesAdapter extends RecyclerView.Adapter<expensesAdapter.expHolder> {
private ArrayList<expenses> expensesArrayList;
private Context context;
public expensesAdapter(ArrayList<expenses> expensesArrayList, Context context) {
this.expensesArrayList = expensesArrayList;
this.context = context;
}
@NonNull
@Override
public expensesAdapter.expHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.expensesitems,parent,false);
return new expHolder(v);
}
@Override
public void onBindViewHolder(@NonNull expensesAdapter.expHolder holder, int position) {
expenses expenses = expensesArrayList.get(position);
holder.catName.setText(expenses.getCategory());
holder.catAmont.setText(expenses.getAmount());
}
@Override
public int getItemCount() {
return expensesArrayList.size();
}
class expHolder extends RecyclerView.ViewHolder {
private final TextView catName,catAmont;
public expHolder(@NonNull View itemView) {
super(itemView);
catName = itemView.findViewById(R.id.expCategory);
catAmont =itemView.findViewById(R.id.expAmount);
}
}
}
Это класс расходов
public class expenses {
String Category;
String Date;
String Email;
String Amount;
String Description;
String expID;
public expenses(String category, String date, String email, String amount, String description, String expID) {
Category = category;
Date = date;
Email = email;
Amount = amount;
Description = description;
this.expID = expID;
}
public expenses(){}
public String getCategory() {
return Category;
}
public void setCategory(String category) {
Category = category;
}
public String getDate() {
return Date;
}
public void setDate(String date) {
Date = date;
}
public String getEmail() {
return Email;
}
public void setEmail(String email) {
Email = email;
}
public String getAmount() {
return Amount;
}
public void setAmount(String amount) {
Amount = amount;
}
public String getDescription() {
return Description;
}
public void setDescription(String description) {
Description = description;
}
public String getExpID() {
return expID;
}
public void setExpID(String expID) {
this.expID = expID;
}
}
Но мне нужен такой результат:

Я хочу, чтобы в recyclerview была указана сумма суммы по категориям. В моем коде это отображается только отдельно.
Пожалуйста, помогите мне понять это!
обновил вопрос. помогите, если знаете решение. Спасибо!
Укажите схему базы данных, а не результаты запроса.
Хорошо. повторно загружен. пожалуйста, проверьте!




Это связано с тем, что для каждого документа в коллекции базы данных вы добавляете его в свой список расходов. Вы можете сохранить все категории расходов, а затем добавить их в список адаптеров.
...//other code
expensesArrayList.clear();
List<DocumentSnapshot> list = queryDocumentSnapshots.getDocuments();
// create a map for category wise total expense
Map<String,Integer> map = new HashMap<>();
for (DocumentSnapshot ds : list){
expenses expenses = ds.toObject(expenses.class);
String category = expenses.getCategory();
int amount = Integer.parseInt(expenses.getAmount());
if (map.containsKey(category))
amount += map.get(category);
map.put(category, amount);
}
// Iterate over map and add expense for each category
for (Map.Entry<String,Integer> entry : map.entrySet()){
// add a constructor in your expenses class for this
expenses categoryExpense = new expenses(entry.getKey(), String.valueOf(entry.getValue()));
expensesArrayList.add(categoryExpense);
}
adapter.notifyDataSetChanged();
...// other code
// In you expenses.java class add this constructor as well
public expenses(String category, String amount) {
Category = category;
Amount = amount;
}
Однако с этой реализацией могут возникнуть проблемы, если у вас есть похожие категории с разными именами, такими как телефон и телефон, они будут считаться разными категориями. Я бы предложил вам перепроектировать вашу реализацию с классами enum для категорий.
Быстрые советы:
Я пробовал это, но возникла ошибка с конструктором в классе расходов. то, что мне нужно, хочу получить категорию мудрой суммы отдельно. Спасибо!
Я обновил свой ответ в соответствии с вашими требованиями. Вам также придется добавить еще один конструктор в свой класс расходов, или вы можете использовать старый с нулевыми значениями для оставшихся полей.
map.put(category, map.getOrDefault(category, 0) + Integer.parseInt(expenses.getAmount())); есть ошибка в этом коде. Ошибка: java.lang.NoSuchMethodError: No interface method getOrDefault(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; in class Ljava/util/Map; or its super classes (declaration of 'java.util.Map' appears in /system/framework/core-libart.jar)Я не уверен, почему метод map.getOrDefault() не работает. Вместо этого вы можете использовать обычный метод map.containsKey(). Я обновил код соответственно.
Это сработало! Большое спасибо за ваше терпение, пока не разрешите это. Я очень новичок в Android, только начал, это мне очень помогает. И спасибо за ваше руководство, я исправил эти ошибки. благословение!
Проблема в вашем коде заключается в том, что у вас в классе expenses есть поле с именем Category и геттер с именем getCategory(),, что неверно, поскольку Firebase ищет в базе данных поле с именем category, а не Category. Видите строчную c букву и заглавную C?
Firebase SDK сопоставляет ваш объект Java и свойства JSON в Cloud Firestore на основе соглашений об именах свойств JavaBean. При этом существует несколько решений этой проблемы, но вот самые простые:
public class Expenses {
String category;
String date;
String email;
String amount;
String description;
String expId;
public expenses(String category, String date, String email, String amount, String description, String expId) {
this.category = category;
this.date = date;
this.email = email;
this.amount = amount;
this.description = description;
this.expId = expId;
}
public Expenses(){}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getAmount() {
return Amount;
}
public void setAmount(String amount) {
this.amount = amount;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getExpId() {
return expId;
}
public void setExpId(String expId) {
this.expId = expId;
}
}
@PropertyName перед геттерами, чтобы сопоставить поля в вашем классе с именем, существующим внутри базы данных:public class expenses {
String Category;
String Date;
String Email;
String Amount;
String Description;
String expID;
public expenses(String category, String date, String email, String amount, String description, String expId) {
Category = category;
Date = date;
Email = email;
Amount = amount;
Description = description;
this.expID = expID;
}
public expenses(){}
@PropertyName("Category")
public String getCategory() {
return Category;
}
public void setCategory(String category) {
Category = category;
}
@PropertyName("Date")
public String getDate() {
return Date;
}
public void setDate(String date) {
Date = date;
}
@PropertyName("Email")
public String getEmail() {
return Email;
}
public void setEmail(String email) {
Email = email;
}
@PropertyName("Amount")
public String getAmount() {
return Amount;
}
public void setAmount(String amount) {
Amount = amount;
}
@PropertyName("Description")
public String getDescription() {
return Description;
}
public void setDescription(String description) {
Description = description;
}
public String getExpID() {
return expID;
}
public void setExpID(String expID) {
this.expID = expID;
}
}
P.S. Также обратите внимание, что я переименовал класс с expenses на Expenses, на Соглашения об именах Java.
Привет, Дулита. Вы пробовали мое решение выше, оно работает для вас?
Пожалуйста, отредактируйте свой вопрос и добавьте структуру вашей базы данных в виде снимка экрана. Пожалуйста, добавьте содержание вашего
expensesкласса.