Reputation: 886
I was trying to implement Room for persistent data storage in java. But I ran into problems with it.
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();
}
with the above the app crashes with error:
java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
whenever I try to insert a data into the database.
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();
}
changed the return type to hold ListenableFuture<Integer>
because official doc says to do so.
The app does not build successfully and shows the following error:
error: Not sure how to handle insert method's return type.
So, my question is how can I correctly and successfully insert data in the database using room with java.
Please help.
Upvotes: 0
Views: 221
Reputation: 886
After wandering on the internet for ages, I came to know that it is possible to write insert query using following 2 methods:
- 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();
}
- 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();
}
Upvotes: 0
Reputation: 131
For working with Room in UI thread you need initialize database as below
database = Room.databaseBuilder(YOUR_CONTEXT, AppDatabase.class, "database")
.allowMainThreadQueries() //this string need for working in UI thread
.build();
But it not recommended to do in production code
And as Dominik Wuttke said you may do asynhronous work with coroutines or RxJava instead of ListenableFuture.
Upvotes: 0
Reputation: 555
You basically created the database with your first run of the app and were trying to access the database on the main thread which throws an error.
When you changed your database and tried to run the app, you changed the database scheme without providing a migration to the new version.
The solution for the changed database is, open the device manager and delete your database, this forces the system to create a new instance of the database with your updated database scheme. Or you can provide a migration which is necessary when you are updating the database scheme for an app already in production
The solution for the error, that you are trying to access the database from the mainthread is, that database operations need to be handled asynchronous and are not allowed to block the main thread.
You need to create a thread where you access the database, with kotlin you can simply create a coroutine and run the operation as a coroutine. With Java you should make use of RXJava
Upvotes: 0