Skip to content
Advertisement

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

I am creating a simple expence tracker. I can add items to the database and view them in a recyclerview. But when I try to SUM all values from a column, it only return 0 instead of the sum of all the values. First of all, here’s the column which values I am trying to sum together.

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

And here is the Dao Query:

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

Item is the name of my Entity class

I am using AsyncTask like this:

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;
    }

And in my Main View Model I create the method

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

Which I then call in my Activity class.

I am calling this method in onCreate like this:

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

I have logged the value of tempSum, and it is 0 when onCreate is being called.

Does anyone know what could be the problem? Is there anything wrong with my dao Query?


EDIT 1:

I changed it so I access getTotalSum directly, instead of using Async. In my Activity, I then observe the value like this:

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

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

But it tells me: Attempt to invoke virtual method ‘int java.lang.Integer.intValue()’ on a null object reference. I do not get how sumAllItems is null?


EDIT 2.

Full Error output from the error on 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$2.onChanged(MyBudgetActivity.java:100)
        at com.example.pf.Activities.MyBudgetActivity$2.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$1.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)

EDIT 3 – SOLUTION

With the help from Stephane Piedjou, the solution was to create an observer. The problem in Edit 1 was that I did not observe the data directly from dao.

I changed this and it worked.

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

Advertisement

Answer

Your query is run asynchronously. task.execute() will run the operation on another thread and when you assign the sumValue (task.sumValue) it is still null as the other thread has not completed its operation. A solution is in your dao instead of returning int your return a live data

public LiveData<Integer> getTotalSum();

In your repository instead of calling AsyncTask you call the getTotaSum() directly

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

And you can observe for the result in your activity with something similar to this.

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

For more info about live data see here

Advertisement