道室数据库。如何对所有金额求和并将其作为 TextView 查看?

Dao Room database. How to SUM all the amounts and view it as a TextView?

我正在创建一个简单的费用跟踪器。 我可以将项目添加到数据库并在 recyclerview 中查看它们。 但是当我尝试对列中的所有值求和时,它只是 return 0 而不是所有值的总和。 首先,这是我要汇总的值的列。

@ColumnInfo(name = "amount")
    public int Amount;`

这是 Dao 查询:

@Query("SELECT SUM(amount) as total FROM Item")
    public int getTotalSum();

项目是我的实体的名称class

我是这样使用 AsyncTask 的:

private static class GetTotalAsyncTask extends AsyncTask<Integer, Void,
            Void>{

        private DaoInterface asyncTaskDao;
        private int sumValue;

        private GetTotalAsyncTask(DaoInterface noteDao) {
            this.asyncTaskDao = noteDao;
        }
        @Override
        protected Void doInBackground(Integer... params) {
            sumValue = asyncTaskDao.getTotalSum();
            return null;
        }

    }

public int sumAllItems(){
        GetTotalAsyncTask task = new GetTotalAsyncTask(dao);
        task.execute();
        String tempSum = task.sumValue;
        return tempSum;
    }

然后在我的主视图模型中创建方法

public int sumAllItems() {
        return repository.sumAllItems();
    }

然后我在 Activity class.

中调用

我在 onCreate 中调用这个方法是这样的:

int myTotaltext = mainViewModel.sumAllItems();
totalAmount.setText(myTotaltext + " kr");

我记录了tempSum的值,调用onCreate时为0。

有谁知道可能是什么问题?我的dao查询有什么问题吗?


编辑 1:

我更改了它,所以我直接访问 getTotalSum,而不是使用 Async。 在我的 Activity 中,我观察到这样的值:

final Observer<Integer> sumObserver = new Observer<Integer>() {
            @Override
            public void onChanged(Integer totalSum) {
                totalAmount.setText(totalSum);
            }
        };

        mainViewModel.sumAllItems().observe(this, sumObserver);

但它告诉我:尝试在空对象引用 上调用虚拟方法'int java.lang.Integer.intValue()'。 我不明白 sumAllItems 为何为空?


编辑 2.

EDIT1 上的错误输出完整错误

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.pf, PID: 26498
    java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Integer.intValue()' on a null object reference
        at com.example.pf.Activities.MyBudgetActivity.onChanged(MyBudgetActivity.java:100)
        at com.example.pf.Activities.MyBudgetActivity.onChanged(MyBudgetActivity.java:97)
        at androidx.lifecycle.LiveData.considerNotify(LiveData.java:133)
        at androidx.lifecycle.LiveData.dispatchingValue(LiveData.java:151)
        at androidx.lifecycle.LiveData.setValue(LiveData.java:309)
        at androidx.lifecycle.LiveData.run(LiveData.java:93)
        at android.os.Handler.handleCallback(Handler.java:888)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:213)
        at android.app.ActivityThread.main(ActivityThread.java:8178)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1101)

编辑 3 - 解决方案

在 Stephane Piedjou 的帮助下,解决方案是创建一个观察者。 Edit 1的问题是我没有直接从dao观察数据。

我改变了这个并且它起作用了。

mainViewModel.repository.dao.getTotalSum().observe(this, new Observer<Integer>() {
            @Override
            public void onChanged(Integer integer) {
                totalAmount.setText(integer + " kr");
            }
        });

您的查询是 运行 异步查询。 task.execute() 将 运行 另一个线程上的操作,当您分配 sumValue (task.sumValue) 时它仍然为空,因为另一个线程尚未完成其操作。 解决方案在您的 dao 中,而不是 returning int 您的 return 实时数据

public LiveData<Integer> getTotalSum();

在您的存储库中,您直接调用 getTotaSum() 而不是调用 AsyncTask

public LiveData<Integer> sumAllItems(){
    return dao.getTotalSum();
}

你可以在你的 activity 中用类似的东西观察结果。

viewModel.getTotalSum().observe(getViewLifecycleOwner(), (int sum)->{
    // totalAmount.setText(sum + " kr");
});

有关实时数据的详细信息,请参阅 here

sumAllItems() 方法启动一个 AsyncTask 来执行异步操作。但随后它会尝试在下一行读取此操作的值(当它尚未准备好时)。在 AsyncTask 中重写 onPostExecute(),这是一个回调,指示 AsyncTask 已完成。通过该方法,您将能够获取结果。