Почему операция удаления помещения (с RxJava) выдает ошибку потока пользовательского интерфейса, даже если указать другой поток подписки? - PullRequest
0 голосов
/ 17 февраля 2019

Так просто, использование DAO

@Query("DELETE FROM Things WHERE someIdOfTheThing IN (:listOfId)")
abstract fun deleteThings(listOfId: MutableList<String>): Maybe<Int>

,

mDisposables.add(mThingsDao
    .deleteThings(listOfId)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({
         ...
     }, {
         ...
     })
)

и ошибка,

// Cannot access database on the main thread since it may potentially lock the UI for a long period of time.

Простая идея, о которой я думал, это указать subscribeOn(Schedulers.io()), а затем отдайте всю работу магическим рукам Rx, но не получилось.

Так что же мне не хватает? 1013 *


После обертывания, как показано ниже, и использования deleteThingsWrapped,начал работать.Но все еще не понимаю, почему первый подход не сработал

open fun deleteThingsWrapped(listOfId: MutableList<String>): Maybe<Int> {
    return Maybe.create(object : MaybeOnSubscribe<Int> {
        override fun subscribe(emitter: MaybeEmitter<Int>) {
            emitter.onSuccess(deleteThings(listOfId))
        }
    })
}

@Query("DELETE FROM Things WHERE someIdOfTheThing IN (:listOfId)")
abstract fun deleteThings(listOfId: MutableList<String>): Maybe<Int>

Ответы [ 2 ]

0 голосов
/ 18 февраля 2019

Это ошибка, она уже исправлена ​​и будет выпущена с 2.1.0-alpha05

0 голосов
/ 17 февраля 2019

Гораздо более интересный вопрос, чем кажется <3 </p>

Чтобы решить вашу проблему, мы должны взглянуть на код, сгенерированный Room - для следующего:

@Transaction
@Query("DELETE FROM plants WHERE id IN (:listOfId)")
abstract fun deleteThings(listOfId: MutableList<String>): Maybe<Int>

Сгенерированный код:

  @Override
  public Maybe<Integer> deleteThings(final List<String> listOfId) {
    StringBuilder _stringBuilder = StringUtil.newStringBuilder();
    _stringBuilder.append("DELETE FROM plants WHERE id IN (");
    final int _inputSize = listOfId.size();
    StringUtil.appendPlaceholders(_stringBuilder, _inputSize);
    _stringBuilder.append(")");
    final String _sql = _stringBuilder.toString();
    SupportSQLiteStatement _stmt = __db.compileStatement(_sql);
    int _argIndex = 1;
    for (String _item : listOfId) {
      if (_item == null) {
        _stmt.bindNull(_argIndex);
      } else {
        _stmt.bindString(_argIndex, _item);
      }
      _argIndex ++;
    }
    return Maybe.fromCallable(new Callable<Integer>() {
      @Override
      public Integer call() throws Exception {
        __db.beginTransaction();
        try {
          final java.lang.Integer _result = _stmt.executeUpdateDelete();
          __db.setTransactionSuccessful();
          return _result;
        } finally {
          __db.endTransaction();
        }
      }
    });
  }

Итак, мы видим, что сама операция находится внутри блока Maybe.fromCallable, который является частью, на которую будет влиять subscribeOn(Schedulers.io()).Итак, если executeUpdateDelete(); выполняется в фоновом потоке, почему вы получаете исключение?


См. Эту строку:

SupportSQLiteStatement _stmt = __db.compileStatement(_sql);

Если мыпроверьте внутреннюю часть этого метода ....

/**
 * Wrapper for {@link SupportSQLiteDatabase#compileStatement(String)}.
 *
 * @param sql The query to compile.
 * @return The compiled query.
 */
public SupportSQLiteStatement compileStatement(@NonNull String sql) {
    assertNotMainThread(); // <-- BOOM!
    return mOpenHelper.getWritableDatabase().compileStatement(sql);
}

Таким образом, очевидно, что даже при составлении запроса утверждается, что он не находится в главном потоке, поэтому наличие Maybe не имеет значения;блок вне Maybe.fromCallable выполняется в текущем потоке независимо от того, что вы делаете.



Это можно решить, выполнив «синхронно исполняемую часть» для выполнения в фоновом потокетоже.

mDisposables.add(
    Maybe.defer { 
        mThingsDao.deleteThings(listOfId)
                         .subscribeOn(Schedulers.io())
    }.subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({
       ...
    }, {
       ...
    })
)
...