Комната - удаление выполняется после вставки новых значений - PullRequest
0 голосов
/ 16 ноября 2018

Я изучаю Rxjava2 и пытаюсь интегрировать Библиотеку комнат с Rxjava2. Проблема в том, что у меня заполненная таблица, и каждый раз, когда я вхожу в приложение, мне нужно удалить эту таблицу, а затем вставить новый контент в базу данных. Отдельно удаление и вставка работают нормально, но когда я пытаюсь вставить новые значения после удаления содержимого таблицы, метод delete удаляет все новые значения .. (некоторые части кода находятся в kotlin, а другие - в java)
Я уже пробовал это: RxJava2 + Комната: данные не вставляются в БД после вызова clearAllTables () , но безуспешно ..

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

Мой класс, который вызывает 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)
                }
    }
}

Метод, который вызывается, когда я нажимаю кнопку входа в систему

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

Любые исправления в моем коде также приветствуются :), но основная проблема заключается в том, что метод delete удаляет все новые значения вставки и должен удалять только старые значения.

Ответы [ 2 ]

0 голосов
/ 17 ноября 2018

Так у вас остались какие-либо значения после нажатия кнопки?Я пока не могу комментировать, поэтому прошу здесь, извините за это

0 голосов
/ 17 ноября 2018

Вы делаете два асинхронных вызова: один для удаления пользователей, а другой для их повторной вставки. Однако даже если вы сначала вызываете метод callDao.clean();, а после этого вызываете callDao.insertInDB(list);, не гарантируется, что операция clean() будет выполнена до операции insertInDB() (потому что именно так работают асинхронные вызовы).

Вот что происходит:

Async calls without waiting

Вместо этого вам следует связывать асинхронные вызовы таким образом, чтобы второй вызывался, как только вы узнали, что первый уже завершен.

Chained async calls

Как этого добиться, используя RxJava и Completable? Использование оператора andThen, как указано в этом ответе

Вам следует изменить методы clean() и insertInDB(), чтобы они возвращали Completables, использовать andThen для их цепочки и затем подписаться.

Простой пример использования RxJava и 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();

Проверяя Logcat после выполнения, вы можете видеть, что операции были выполнены в правильном порядке:

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

После этого Я проверил содержимое базы данных с помощью инструмента Браузер SQLite и увидел, что вставка работает правильно.

SqliteBrowser showing the proper data in the table

Использование @Transaction в DAO

Вы можете получить лучшее решение для вашей проблемы, не используя RxJava. Вместо этого вы можете определить Transaction в своем DAO, используя аннотацию @ Transaction , , как описано в этом посте . Это будет выглядеть примерно так:

ДАО

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

Активность

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

Проверка таблицы

Table using @Transcation

Лично я бы сделал это с аннотацией @Transaction.

...