3

I have a problem with the return of a query in the DAO file. I want to store in the MainActivity a variable for the last ID inserted:

int lastId = taskViewModel.getLastID();

In the DAO I have the following query:

@Query ("SELECT MAX(id) FROM task_table")
int getLastID();

In the ViewModel I have:

public class TaskViewModel extends AndroidViewModel {
private TaskRepository repository;
private int lastID;


public TaskViewModel(@NonNull Application application) {
        super(application);
        repository = new TaskRepository(application);

        lastID = repository.getLastID();
}

   public int getLastID(){
       return lastID;
   }
}

And in the Repository I have:

public class TaskRepository {
    private TaskDao taskDao;

    private int lastID;

    public TaskRepository(Application application) {
        TaskDatabase database = TaskDatabase.getInstance(application);
        taskDao = database.taskDao();
        lastID = taskDao.getLastID();
    }

    public int getLastID() {
        return lastID;
     }
    }

So, the query should return a single int Id from the table, but I occur in an error when I run the app as you can se below:

2019-12-03 15:37:51.096 19684-19684/com.example.todoapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.todoapp, PID: 19684
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.todoapp/com.example.todoapp.MainActivity}: java.lang.RuntimeException: Cannot create an instance of class com.example.todoapp.TaskViewModel
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2817)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
    at android.app.ActivityThread.-wrap11(Unknown Source:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
    at android.os.Handler.dispatchMessage(Handler.java:105)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6541)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
 Caused by: java.lang.RuntimeException: Cannot create an instance of class com.example.todoapp.TaskViewModel
    at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:238)
    at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:164)
    at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:130)
    at com.example.todoapp.MainActivity.onCreate(MainActivity.java:60)
    at android.app.Activity.performCreate(Activity.java:6975)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892) 
    at android.app.ActivityThread.-wrap11(Unknown Source:0) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593) 
    at android.os.Handler.dispatchMessage(Handler.java:105) 
    at android.os.Looper.loop(Looper.java:164) 
    at android.app.ActivityThread.main(ActivityThread.java:6541) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767) 
 Caused by: java.lang.reflect.InvocationTargetException
    at java.lang.reflect.Constructor.newInstance0(Native Method)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:334)
    at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:230)
    at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:164) 
    at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:130) 
    at com.example.todoapp.MainActivity.onCreate(MainActivity.java:60) 
    at android.app.Activity.performCreate(Activity.java:6975) 
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213) 
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770) 
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892) 
    at android.app.ActivityThread.-wrap11(Unknown Source:0) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593) 
    at android.os.Handler.dispatchMessage(Handler.java:105) 
    at android.os.Looper.loop(Looper.java:164) 
    at android.app.ActivityThread.main(ActivityThread.java:6541) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767) 
 Caused by: java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
    at androidx.room.RoomDatabase.assertNotMainThread(RoomDatabase.java:267)
    at androidx.room.RoomDatabase.query(RoomDatabase.java:323)
    at androidx.room.util.DBUtil.query(DBUtil.java:83)
    at com.example.todoapp.TaskDao_Impl.getLastID(TaskDao_Impl.java:1794)
    at com.example.todoapp.TaskRepository.<init>(TaskRepository.java:94)
    at com.example.todoapp.TaskViewModel.<init>(TaskViewModel.java:59)
    at java.lang.reflect.Constructor.newInstance0(Native Method) 
    at java.lang.reflect.Constructor.newInstance(Constructor.java:334) 
    at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:230) 
    at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:164) 
    at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:130) 
    at com.example.todoapp.MainActivity.onCreate(MainActivity.java:60) 
    at android.app.Activity.performCreate(Activity.java:6975) 
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213) 
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770) 
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892) 
    at android.app.ActivityThread.-wrap11(Unknown Source:0) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593) 
    at android.os.Handler.dispatchMessage(Handler.java:105) 
    at android.os.Looper.loop(Looper.java:164) 
    at android.app.ActivityThread.main(ActivityThread.java:6541) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767) 

I think there is something wrong in the return type of the query or how I read the return type. Someone can help me please? Thank you in advance

A LITTLE STEP

With the LiveData I can actually see what is the task's ID that I inserted but i can not use it outside the method onChange. I need this id because I want to create a notification with id == to the id of the task. How can I do it?

UPDATE AND QUESTION If I set a variable like this in the main activity: 'private int lastID;' and I use it inside the onChange method (using the LiveData mode), it can't be used outside the method because I get the error "NullPointException"(see the answer below). I really need a way to simply save the id of the inserted Task and than use it for create the Notification. I don't know how to do.....

HERE THERE ARE MY MAIN FILES

MainActivity, TaskViewModel, TaskRepository, TaskDao

Edric
  • 24,639
  • 13
  • 81
  • 91
Michele
  • 39
  • 1
  • 6
  • Does this answer your question? [Android Room - simple select query - Cannot access database on the main thread](https://stackoverflow.com/questions/44167111/android-room-simple-select-query-cannot-access-database-on-the-main-thread) – momvart Dec 03 '19 at 15:06
  • You are accessing your database on the main thread. That is the problem. – momvart Dec 03 '19 at 15:07
  • So, how can I resolve this problem? – Michele Dec 03 '19 at 15:13

1 Answers1

1

Your error is because you are access dao into main thread " Caused by: java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time."

change to run in background task or livedata

Run in background task example bellow

public class TaskRepository {
    private TaskDao taskDao;

    private int lastID;

    public TaskRepository(Application application) {
        TaskDatabase database = TaskDatabase.getInstance(application);
        taskDao = database.taskDao();
        //run in backgroung task 
         Executors.newSingleThreadExecutor().execute(new Runnable() {
            @Override
            public void run() {
                lastID = repository.getLastID();
            }
        });
    }

    public int getLastID() {
        return lastID;
     }
}

run with live data example bellow

@Query ("SELECT MAX(id) FROM task_table")
LiveData<int> getLastID();

public class TaskViewModel extends AndroidViewModel {
    private TaskRepository repository;
    private int lastID;


    public TaskViewModel(@NonNull Application application) {
        super(application);
        repository = new TaskRepository(application);
    }

    public LiveData<int> getLastID() {
        return taskDao.getLastID();
    }
}

public class TaskRepository {
    private TaskDao taskDao;

    private int lastID;

    public TaskRepository(Application application) {
        TaskDatabase database = TaskDatabase.getInstance(application);
        taskDao = database.taskDao();
    }

    public LiveData<int> getLastID() {
        return taskDao.getLastID();
    }
}


 public class MainActivity extends AppCompatActivity{


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);

        TaskViewModel viewmodel = new TaskViewModel(getApplicationContext())
        dao.getLastID().observe(this, new Observer<int>() {
            @Override
            public void onChanged(int value) {

            }
        });

    }
 } 

edit you task //codice per eseguire operazioni DB sui tread di backgroun perchè Room non ci permette di eseguirle sul Main tread public static class InsertTaskAsyncTask extends AsyncTask{ //abbiamo bisogno che taskDao ci faccia operazioni DB private TaskDao taskDao; private ResultListener onResultListener; private InsertTaskAsyncTask(ResultListener onResultListener,TaskDao taskDao){ this.taskDao = taskDao; this.onResultListener = onResultListener; }

        //unico metodo obbligatorio
        @Override
        protected Void doInBackground(Task... tasks) {
            taskDao.insert(tasks[0]);
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            if (onResultListener != null) {
                onResultListener.onResult();
            }
        }
        interface ResultListener{
            public void onResult();
        }
    }

call use calback

taskViewModel.insert(new TaskRepository.InsertTaskAsyncTask.ResultListener(){
                        @Override
                        public void onResult() {


       Task task = new Task(title, data_calendario, time, priority, type, note, "pending");
        taskViewModel.insert(new TaskRepository.InsertTaskAsyncTask.ResultListener(){
                        @Override
                        public void onResult() {



taskViewModel.getLastID().observe(MainActivity.this, new Observer<Integer>() {
                                @Override
                                public void onChanged(Integer integer) {
                                    System.out.println("Test ID: "+integer);
                                }
                            });
                        }
                    }, task);
Anderson Soares
  • 317
  • 1
  • 3
  • With this method the error doesn't occur but the variable in the MainActivity doesn't contain the correct value of the ID. For example: during the first run of the app it contains always 0, whereas when a task is inserted the ID is always -1 the current. For example, if I inserted the 5th task and this is the first task that i insert after the run of the App, my "lastId" variable is 0; otherwise lastId is equals to 4... How can I resolve this? Thank you very much – Michele Dec 03 '19 at 15:37
  • @Md. Asaduzzaman, with the LiveData it seems to work. One more question: if I want to use the value passed in the onChange method outside that method, how can i do? Do I have ho use a private in var ? – Michele Dec 03 '19 at 15:53
  • onChange is a response of your query, you can create a var in activity and set with response – Anderson Soares Dec 03 '19 at 21:52
  • you can run this on activity as well but seens better use livedata Executors.newSingleThreadExecutor().execute(new Runnable() { @Override public void run() { lastID = repository.getLastID(); } }); – Anderson Soares Dec 03 '19 at 21:54
  • Thank you @andersonrsoares, but if i set a variable like this in the main activity: 'private int lastID;' and I use it inside the onChange method (using the LiveData mode), it can't be used outside the method because I get the error "NullPointException". I really need a way to simply save the id of the inserted Task and than use it for create the Notification. I don't know how to do..... – Michele Dec 03 '19 at 23:13
  • Yes, I'm going to edit the question so you can see all the MainActivity code @andersonrsoares – Michele Dec 04 '19 at 01:32
  • @andersonrsoares did you find any solution for my problem? – Michele Dec 04 '19 at 11:05
  • i updated response you need update your task and use callback to update you view after that – Anderson Soares Dec 04 '19 at 22:09
  • Hi @andersonrsoares, in this way can I save the ID in a variable? Thank you for your help – Michele Dec 05 '19 at 12:44
  • yes, but you need to use this variable after onChanged run, try to call a function there – Anderson Soares Dec 05 '19 at 13:24
  • @michele do you did it? – Anderson Soares Dec 06 '19 at 12:32
  • Yes @andersonrsoares thank you very much, but now I have another problem... can you look at it? https://stackoverflow.com/questions/59221428/wrong-object-selected-with-itemtouchhelper – Michele Dec 07 '19 at 16:48