Room - Delete executes after I insert new values

僤鯓⒐⒋嵵緔 提交于 2020-05-25 07:17:14

问题


I'm studying Rxjava2 and I'm trying to integrate the Room Library with Rxjava2. The problem is: I have a populated table and every time I login in the app, I need to delete this table and then insert a new content in database. Separately, the delete and insert works fine, but when I try to insert new values after I delete the table content, the delete method deletes all the new values.. (some parts of the code is in kotlin and others in java)
I already tried this: RxJava2 + Room: data is not being inserted in DB after clearAllTables() call, but no success..

DAO

@Dao
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(list:List<Something>)

@Query("DELETE FROM SomethingTable")
fun delete()

@Query("SELECT * FROM SomethingTable")
fun getAll(): Flowable<List<Something>>

My class that calls the DAO (CallDao)

//insert
fun insertInDB(list: List<Something>) {
    Completable.fromAction {
        dbDAO!!.insert(list)
    }.observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.io())
            .subscribe()
}

//delete
fun clean() {
    Completable.fromAction {
        dbDAO!!.delete()
    }.observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.single())
            .subscribe()
}

//search all
fun findAll(): Observable<List<Something>>? {
    return Observable.create { subscriber ->
        dbDAO!!.getAll()
                .subscribeOn(Schedulers.io())
                .subscribe {it->
                    subscriber.onNext(it)
                }
    }
}

Method that is called when I click in login button

private void clearAndInsertInDB() {
CallDao callDao= new CallDao(getActivity());
//delete all table values
callDao.clean();

Something sm = new Something("test1", "test2");
ArrayList<Something> list = new ArrayList<>();
list.add(sm);
list.add(sm);
//insert new values
callDao.insertInDB(list);

//get all new values in DB
callDao.findAll()
      .observeOn(AndroidSchedulers.mainThread())
      .subscribe(res -> {
      //here gives me a IndexOutOfBoundsException
      Log.d("logDebug", res.get(0).getCodeExemple());
    });
}

Any corrections in my code is also welcome :) , but the main problem is that the delete method deletes all the new insert values and it should delete only the old values.


回答1:


You are making two asynchronous calls: one to delete the users and another to insert them again. However, even though you call first the callDao.clean(); method and after that you call callDao.insertInDB(list); , it is not guaranteed that the clean() operation will finish before the insertInDB() operation (because that's how asynchronous calls work).

This is what is happening:

Instead, you should chain your async calls , in such a way that the second one gets called as soon as you know that the first one has already finished.

How to achieve that using RxJava and Completable? Using the andThen operator as stated in this answer

You should modify your clean() and insertInDB() methods to return the Completables, use andThen to chain them, and then subscribe.

Simple example using RxJava and andThen()

FakeDatabase db = Room.databaseBuilder(this, FakeDatabase.class, "fake.db")
                      .fallbackToDestructiveMigration()
                      .build();

UserDao userDao = db.userDao();

User user1 = new User("Diego", "Garcia Lozano", "diegogarcialozano@fake.com");
User user2 = new User("Juan", "Perez", "juanperez@fake.com");
User user3 = new User("Pedro", "Lopez", "pedrolopez@fake.com");
List<User> users = new ArrayList<>();
users.add(user1);
users.add(user2);
users.add(user3);

Completable deleteAllCompletable = Completable.fromAction(userDao::deleteAll);
Completable insertUserCompletable = Completable.fromAction(() -> userDao.insertAll(users));

deleteAllCompletable
            .andThen(Completable.fromAction(() -> System.out.println("Delete finished")))
            .andThen(insertUserCompletable)
            .andThen(Completable.fromAction(() -> System.out.println("Insert finished")))
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.single())
            .subscribe();

Checking the Logcat after execution, you can see that the operations were executed in the proper order:

2018-11-19 16:07:02.056 10029-10047/? I/System.out: Delete finished
2018-11-19 16:07:02.060 10029-10047/? I/System.out: Insert finished

Afterwards, I checked the content of the database using the tool SQLite Browser and saw that the insert worked properly.

Using @Transaction in the DAO

You can get a better solution for your problem without using RxJava at all. Instead, you can define a Transaction in your DAO using the @Transaction annotation, as explained in this post. It would look something like this:

Dao

@Dao
public abstract class UserDao {

    @Transaction
    public void deleteAndCreate(List<User> users) {
        deleteAll();
        insertAll(users);
    }

    @Query("DELETE FROM User")
    public abstract void deleteAll();

    @Insert
    public abstract void insertAll(List<User> users);
}

Activity

Completable.fromAction(() -> userDao.deleteAndCreate(users))
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.single())
            .subscribe();

Checking the table

Personally, I would do it with the @Transaction annotation.




回答2:


So do You have any values left after pressing the button? I am not yet able to comment so I am asking here, sorry for that



来源:https://stackoverflow.com/questions/53344456/room-delete-executes-after-i-insert-new-values

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!