@rawQuery с ViewModel

#android #android-room #android-viewmodel

#Android #android-комната #android-viewmodel

Вопрос:

Я следил за этой комнатой с помощью руководства по просмотру, и все работает так, как ожидалось. Теперь я пытаюсь реализовать @rawQuery и отобразить живые данные с помощью ViewModel. Я хочу отобразить список элементов, которые имеют определенное значение столбца (в данном случае строку). В этой документации этот код, похоже, является решением для моей желаемой функции приложения:

 @Dao
 interface RawDao {
     @RawQuery(observedEntities = User.class)
     LiveData<List<User>> getUsers(SupportSQLiteQuery query);
 }
 LiveData<List<User>> liveUsers = rawDao.getUsers(
     new SimpleSQLiteQuery("SELECT * FROM User ORDER BY name DESC"));
  

Я хочу, чтобы мой запрос на чтение создавался во время выполнения, когда значение NameColumn передается в simpleSQLiteQuery(String nameColumn) функцию, которая возвращает new SimpleSQLiteQuery .

Вот мой код:

Dao

 @Dao
public interface ShotDao {

@RawQuery(observedEntities = Shot.class)
LiveData<List<Shot>> getNameColumn(SupportSQLiteQuery supportSQLiteQuery);

}
  

Репозиторий

     private ShotDao mShotDao;
    private LiveData<List<Shot>> mNameColumn;
    private SimpleSQLiteQuery mSimpleSQLiteQuery;

    public ShotRepository(Application application) {
        WrappShotDatabase database = WrappShotDatabase.getDatabase(application);
        mShotDao = database.shotDao();
        mNameColumn = mShotDao.getNameColumn(mSimpleSQLiteQuery);
    }

    public LiveData<List<Shot>> getNameColumn (SimpleSQLiteQuery simpleSQLiteQuery) {
        this.mSimpleSQLiteQuery = simpleSQLiteQuery;
        return mNameColumn;
    }
  

ViewModel

     private ShotRepository mRepository;
    private LiveData<List<Shot>> mNameColumn;
    private SimpleSQLiteQuery mSimpleSQLiteQuery;

    public ShotViewModel(Application application) {
        super(application);
        mRepository = new ShotRepository(application);
        mNameColumn = mRepository.getNameColumn(mSimpleSQLiteQuery);
    }

    public LiveData<List<Shot>> getNameColumn (SimpleSQLiteQuery simpleSQLiteQuery) {
        this.mSimpleSQLiteQuery = simpleSQLiteQuery;
        return mNameColumn;
    }
  

Активность

         String columnName = mColumnName;

        shotViewModel = ViewModelProviders.of(this).get(ShotViewModel.class);
        shotViewModel.getNameColumn(simpleSQLiteQuery(columnName)).observe(this, new Observer<List<Shot>>() {
            @Override
            public void onChanged(@Nullable List<Shot> shots) {
                mShotAdapter.submitList(shots);
            }
        });
  

Метод SimpleSQLiteQuery

  private SimpleSQLiteQuery simpleSQLiteQuery(String nameColumn) {
        String select = "SELECT * FROM ";
        String tableName = "shots";
        String where = " WHERE nameColumn="";
        String close = """;
        return new SimpleSQLiteQuery(select   tableName   where   nameColumn   close);
    }
  

При создании Activity происходит сбой моего приложения, и я получаю сообщение об ошибке:

 java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.String android.arch.persistence.db.SupportSQLiteQuery.getSql()' on a null object reference
  

Я не совсем понимаю, почему мой объект не создан и когда это должно быть. Logcat также указывает строки A и B в ShotDao_Impl.java сгенерированный исходный файл.

 @Override
  public LiveData<List<Shot>> getNameColumn(SupportSQLiteQuery supportSQLiteQuery) {
    final SupportSQLiteQuery _internalQuery = supportSQLiteQuery;
    return new ComputableLiveData<List<Shot>>() { // row A
      private Observer _observer;
      @Override
      protected List<Shot> compute() {
        if (_observer == null) {
          _observer = new Observer("shots") {
            @Override
            public void onInvalidated(@NonNull Set<String> tables) {
              invalidate();
            }
          };
          __db.getInvalidationTracker().addWeakObserver(_observer);
        }
        final Cursor _cursor = __db.query(_internalQuery); // row B
        try {
          final List<Shot> _result = new ArrayList<Shot>(_cursor.getCount());
          while(_cursor.moveToNext()) {
            final Shot _item;
            _item = __entityCursorConverter_comExampleAndroidWrappDatabaseShot(_cursor);
            _result.add(_item);
          }
          return _resu<
        } finally {
          _cursor.close();
        }
      }
    }.getLiveData();
  }
  

Ответ №1:

Эта строка в viewmodel выдает ошибку. Вы устанавливаете mSimpleSQLiteQuery для room db значение null.

mNameColumn = mRepository.getNameColumn(mSimpleSQLiteQuery);

Вы должны удалить строку выше из viewmodel и изменить getNameColumn() функцию следующим образом:

 public LiveData<List<Shot>> getNameColumn (SimpleSQLiteQuery simpleSQLiteQuery) {
    return mRepository.getNameColumn(mSimpleSQLiteQuery);;
}
  

Редактировать:

Вы можете упростить свой код, изменив свой DAO. Вы можете передавать параметры прямо в DAO.

Например.

 @Query("SELECT * FROM shots WHERE nameColumn = :columnName")
LiveData<List<Shot>> getNameColumn(String columnName);
  

с помощью этой функции вы можете извлекать данные shots в соответствии с именем столбца

Комментарии:

1. Спасибо за решение и пример упрощения!

Ответ №2:

mNameColumn Живые данные в ViewModel создаются с помощью null mSimpleSQLiteQuery во время выполнения конструктора ViewModel. Вы устанавливаете это в getNameColumn , но обратите внимание, что ваши livedata не знают об этом новом значении.

Следовательно, impl ShotDao for LiveData<List<Shot>> getNameColumn(SupportSQLiteQuery supportSQLiteQuery); получает null SupportSQLiteQuery, что приводит к сбою.