无法弄清楚如何使用 pojo 从一个 Room 实体构建 ViewPager2 的数据

Cannot figure out how to structure data for ViewPager2 from one Room entity using pojo

我是 Android 的新手,需要一些帮助。 我正在制作一个管理费用的应用程序。我有房间数据库 table 'expenses':

CostEntry.java

@Entity(tableName = "expenses")
public class CostEntry {

    @PrimaryKey(autoGenerate = true)
    private int id;
    private String category;
    private String name;
    private int cost;
    private String date;
    private String currency;

//....
}

我的activity显示了某个日期的所有费用。 现在,我想制作 viewpager2,其页面将显示所有类别及其总和 - 特别是货币(页数等于不同货币的数量)。

所以,我做了一个简单的pojo:

TotalCostPojo.java

public class TotalCostPojo {

    public TotalCostPojo() {
    }

    private String currency;
    private List<String> category;
    private List<Integer> categoryCosts;


    public String getCurrency() {
        return currency;
    }

    public void setCurrency(String currency) {
        this.currency = currency;
    }

    public List<String> getCategory() {
        return category;
    }

    public void setCategory(List<String> category) {
        this.category = category;
    }

    public List<Integer> getCategoryCosts() {
        return categoryCosts;
    }

    public void setCategoryCosts(List<Integer> categoryCosts) {
        this.categoryCosts = categoryCosts;
    }
}

但是,我得到一个错误:

error: Cannot figure out how to read this field from a cursor. private List categoryCosts; private List category;

这是我的道:

@Query("SELECT DISTINCT currency, category, SUM (cost) AS categoryCosts FROM expenses WHERE date = :date group by category")
    LiveData<List<TotalCostPojo>> loadTotalCategoryCosts(String date);

我之前也遇到过类似的问题,后来用@Relation注解解决了。我不知道如何在这里做,因为没有超过一个实体。

提前致谢。

我认为在 Room 中没有您想要的内置方式(正如您所写的那样,@Relation 注释不是这种情况,因为没有两个真正的表可以连接)。 我只能建议您可以尝试的解决方法(可能是一个明显的样板,您期望更优雅,但仍然是一种方法):

  1. 添加 class CostPojo 字段:货币(字符串)、类别(字符串)、类别成本(整数)。
  2. loadTotalCategoryCosts 中的返回值类型更改为 List<CostPojo>
LiveData<List<CostPojo>> loadTotalCategoryCosts(String date);
  1. 要为您的 ViewPager 获取所需的数据结构,您必须创建自己的从 List<CostPojo>List<TotalCostPojo> 的转换函数。为此,您可以使用 LiveData Transformations 或例如将静态辅助方法 convertToTotalCost 添加到您的 CostPojo class (输入 - List<CostPojo>,输出 - List<TotalCostPojo>).

更新 对于那些感兴趣的人 - 基于问题作者的这个答案的最终解决方案在单独的答案中

以上答案绝对正确,我只是想添加一些代码来阐明转换函数并将 List<CostPojo> 转换为 List<TotalCostPojo>。也许有人会发现有用,我以前对此一无所知。另外,如果我犯了一些错误,或者如果我可以做得更好,请指出。

TotalCostPojo.java

public class TotalCostPojo {

    public TotalCostPojo() {
    }

    private String currency;
    private Map<String, Integer> categoryCosts;

所有其他内容都在 ViewModel 中(从数据库获取 LiveData 并转换为 List<TotalCostPojo:

public class DailyExpensesViewModel extends ViewModel {

    private LiveData<List<CostPojo>> categoryCosts;

    public DailyExpensesViewModel(CostDatabase database, String date) {
        categoryCosts = database.costDao().loadCategoryCosts(date);
    }

    public LiveData<List<TotalCostPojo>> getTotalCategoryCosts() {
       return Transformations.map(categoryCosts, this::convertToTotalCost);
    }

    private List<TotalCostPojo> convertToTotalCost(List<CostPojo> costPojo) {

        List<TotalCostPojo> totalCostPojos = new ArrayList<>();
        List<String> helpPair = new ArrayList<>();
        List<String> helpCurrency = new ArrayList<>();

        for (CostPojo costPojo1 : costPojo) {
            //new TotalCostPojo, new currency
            if (!helpCurrency.contains(costPojo1.getCurrency())) {
                TotalCostPojo obj = new TotalCostPojo();
                obj.setCurrency(costPojo1.getCurrency());
                Map<String, Integer> catCost = new TreeMap<>();
                catCost.put(costPojo1.getCategory(), costPojo1.getCategoryCosts());
                obj.setCategoryCosts(catCost);
                totalCostPojos.add(obj);
                //fill helper lists:
                helpCurrency.add(costPojo1.getCurrency());
                helpPair.add(costPojo1.getCurrency() + costPojo1.getCategory());
                //---------------------------------------
                // same currency, new category
            } else if (!helpPair.contains(costPojo1.getCurrency() + costPojo1.getCategory())) {
                for (TotalCostPojo tcp : totalCostPojos) {
                    if (tcp.getCurrency().equals(costPojo1.getCurrency())) {
                        Map<String, Integer> catCost = tcp.getCategoryCosts();
                        catCost.put(costPojo1.getCategory(), costPojo1.getCategoryCosts());
                        tcp.setCategoryCosts(catCost);
                        //fill helper lists:
                        helpPair.add(costPojo1.getCurrency() + costPojo1.getCategory());
                        //-------------------
                    }
                }
                //same currency, same category, updating costValue
            } else if (helpPair.contains(costPojo1.getCurrency() + costPojo1.getCategory())) {
                for (TotalCostPojo tcp : totalCostPojos) {
                    if (tcp.getCurrency().equals(costPojo1.getCurrency())) {
                        Map<String, Integer> catCost = tcp.getCategoryCosts();
                       Integer oldValue = catCost.put(costPojo1.getCategory(), costPojo1.getCategoryCosts());
                       if (oldValue != null) {
                           catCost.put(costPojo1.getCategory(), costPojo1.getCategoryCosts() + oldValue);
                           tcp.setCategoryCosts(catCost);
                       }
                    }
                }
            }
        }
        helpPair.clear();
        helpCurrency.clear();
        return totalCostPojos;
    }
}