Как это сделать на recyclerview в Android с помощью firestore

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

Как это сделать на recyclerview в Android с помощью firestore

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

Как это сделать на recyclerview в Android с помощью 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 в Android с помощью firestore

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

Пожалуйста, отредактируйте свой вопрос и добавьте структуру вашей базы данных в виде снимка экрана. Пожалуйста, добавьте содержание вашего expenses класса.

Alex Mamo 08.08.2023 07:47

обновил вопрос. помогите, если знаете решение. Спасибо!

Dulitha Bandaranayake 08.08.2023 09:33

Укажите схему базы данных, а не результаты запроса.

Alex Mamo 08.08.2023 11:16

Хорошо. повторно загружен. пожалуйста, проверьте!

Dulitha Bandaranayake 08.08.2023 12:34
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
4
50
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Это связано с тем, что для каждого документа в коллекции базы данных вы добавляете его в свой список расходов. Вы можете сохранить все категории расходов, а затем добавить их в список адаптеров.

...//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 для категорий.

Быстрые советы:

  1. Имена классов всегда должны быть написаны с заглавной буквы. Так что это должны быть расходы, а не расходы.
  2. Имя поля участника не должно быть написано с заглавной буквы, поэтому это должна быть категория, сумма, адрес электронной почты и т. д.
  3. Сделайте тип данных вашего поля суммы как int или double, чтобы избежать синтаксического анализа и упростить вычисления.

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

Dulitha Bandaranayake 08.08.2023 09:35

Я обновил свой ответ в соответствии с вашими требованиями. Вам также придется добавить еще один конструктор в свой класс расходов, или вы можете использовать старый с нулевыми значениями для оставшихся полей.

Pawan Singh Harariya 08.08.2023 12:47
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)
Dulitha Bandaranayake 09.08.2023 06:50

Я не уверен, почему метод map.getOrDefault() не работает. Вместо этого вы можете использовать обычный метод map.containsKey(). Я обновил код соответственно.

Pawan Singh Harariya 09.08.2023 08:58

Это сработало! Большое спасибо за ваше терпение, пока не разрешите это. Я очень новичок в Android, только начал, это мне очень помогает. И спасибо за ваше руководство, я исправил эти ошибки. благословение!

Dulitha Bandaranayake 09.08.2023 12:14

Проблема в вашем коде заключается в том, что у вас в классе 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.

Привет, Дулита. Вы пробовали мое решение выше, оно работает для вас?

Alex Mamo 09.08.2023 08:15

Другие вопросы по теме