使用 java 在 android 中添加数据存储空间时出现问题

Problem in adding Room for data storage in android using java

我试图在 java 中实现用于持久数据存储的 Room。但是我 运行 遇到了问题。

In first try:

MyDao.java

@Dao
public interface MyDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void addUser(UserDetails userDetails);

}

MyDatabase.java

@Database(entities = {User.class}, version = 1)
public abstract class MyDatabase extends RoomDatabase {

    public abstract MyDao myDao();
}

上面的应用程序崩溃并出现错误:
java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
每当我尝试将数据插入数据库时​​。

In the second try:

MyDao.java

@Dao
public interface MyDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    ListenableFuture<Integer> addUser(UserDetails userDetails);

}

MyDatabase.java

@Database(entities = {User.class}, version = 1)
public abstract class MyDatabase extends RoomDatabase {

    public abstract MyDao myDao();
}

将 return 类型更改为持有 ListenableFuture<Integer> 因为 official doc 要求这样做。 该应用程序未成功构建并显示以下错误:
error: Not sure how to handle insert method's return type.

所以,我的问题是如何使用带 java 的空间正确并成功地将数据插入数据库中。
请帮忙

您基本上是用应用程序的第一个 运行 创建了数据库,并试图在主线程上访问数据库,这会引发错误。

当您更改数据库并尝试 运行 应用程序时,您更改了数据库方案但未提供到新版本的迁移。

更改数据库的解决方案是,打开设备管理器并删除您的数据库,这会强制系统使用您更新的数据库方案创建一个新的数据库实例。或者你可以提供一个迁移,当你更新一个已经在生产中的应用程序的数据库方案时,这是必要的

您试图从主线程访问数据库的错误解决方案是,数据库操作需要异步处理并且不允许阻塞主线程。

您需要创建一个访问数据库的线程,使用 kotlin,您可以简单地创建一个协程,然后 运行 将操作作为协程。使用 Java 你应该使用 RXJava

  1. 要在 UI 线程中使用 Room,您需要按如下方式初始化数据库

     database = Room.databaseBuilder(YOUR_CONTEXT, AppDatabase.class, "database")
         .allowMainThreadQueries() //this string need for working in UI thread
         .build();
    

但不建议在生产代码中这样做

  1. 我从未使用过 Guava,但这里有一个 guide 用于使用 ListenableFuture。

正如 Dominik Wuttke 所说,您可以使用协程或 RxJava 而不是 ListenableFuture 进行异步工作。

在网上折腾了好久,才知道可以用下面两种方法来写insert query:

  1. Using a thread class

Operations.java

public class Operations{

    private MyDao myDao;

    public Operations(Context context){
        MyDatabase db = Room.databaseBuilder(context, MyDatabase.class, "database")
                .fallbackToDestructiveMigration()
                .build();
        myDao = db.myDao();
    }

    public void insertUser(UserDetails userDetails){
        new Thread{
            @override
            public void run(){
                myDao.addUser(userDetails);
            }
        }.start();
    }

}

MyDao.java

@Dao
public interface MyDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void addUser(UserDetails userDetails);

}

MyDatabase.java

@Database(entities = {User.class}, version = 1)
public abstract class MyDatabase extends RoomDatabase {

    public abstract MyDao myDao();
}

  1. Using ExecutorService class

Operations.java

public class Operations{

    private MyDao myDao;

    public Operations(Context context){
        MyDatabase db = Room.databaseBuilder(context, MyDatabase.class, "database")
                .fallbackToDestructiveMigration()
                .build();
        myDao = db.myDao();
    }

    public void insertUser(UserDetails userDetails){
        MyDatabase.databaseWriteExecutor.execute(()->{
               notesDb.notesDao().addNote(note));
           }
    }

}

MyDao.java

@Dao
public interface MyDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void addUser(UserDetails userDetails);

}

MyDatabase.java

@Database(entities = {User.class}, version = 1)
public abstract class MyDatabase extends RoomDatabase {
    
    public static final ExecutorService databaseWriteExecutor =
            Executors.newFixedThreadPool(2);

    public abstract MyDao myDao();
}