如何从DAO查询返回单个int值?

时间:2019-12-03 14:59:59

标签: android android-sqlite android-room dao

我在DAO文件中返回查询时遇到问题。我想在MainActivity中为最后插入的ID存储一个变量:

int lastId = taskViewModel.getLastID();

DAO 中,我有以下查询:

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

ViewModel 中,我有:

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

存储库中,我有:

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

因此,查询应该从表中返回单个int Id,但是在运行应用程序时出现错误,如下所示:

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) 

我认为查询的返回类型或如何读取返回类型有问题。 有人可以帮我吗? 预先谢谢你

小步骤

使用LiveData,我实际上可以看到我插入的任务的ID是什么,但是我无法在onChange方法之外使用它。 我需要此ID,因为我想创建ID ==到任务ID的通知。我该怎么办?

更新和问题 如果我在主要活动中设置了这样的变量:'private int lastID;'并且我在onChange方法中使用它(使用LiveData模式),无法在该方法之外使用它,因为我收到错误“ NullPointException”(请参见下面的答案)。我确实需要一种方法来简单地保存插入的Task的ID,然后将其用于创建Notification。我不知道该怎么办.....

这里有我的主要文件

MainActivity, TaskViewModel, TaskRepository, TaskDao

1 个答案:

答案 0 :(得分:2)

您的错误是因为您正在访问主线程“引起原因:java.lang.IllegalStateException:无法访问主线程上的数据库,因为它可能会长时间锁定UI。”

更改为在后台任务或实时数据中运行

在下面的后台任务示例中运行

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

使用实时数据示例运行

@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) {

            }
        });

    }
 } 

编辑任务      //根据每个操作员的编码,对DB sui踏步操作进行后台操作         公共静态类InsertTaskAsyncTask扩展了AsyncTask {            // abbiamo bisogno che taskDao ci faccia Operazioni DB             私人TaskDao taskDao;             私有ResultListener onResultListener;             私人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();
        }
    }

致电使用回拨

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