@RawQuery 与 ViewModel

@RawQuery with ViewModel

我遵循了这个Room With a View tutorial and everything works as expected. Now I'm trying to implement @RawQuery and display LiveData with ViewModel. I want to display a list of items that have a certain column value (in this case a String). In this documentation这段代码似乎是我想要的应用程序功能的解决方案:

@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) 函数 returns new SimpleSQLiteQuery.

时在 运行 时构建我的读取查询

这是我的代码:

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

Activity

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

简单的SQLiteQuery方法

 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 还指出了 ShotDao_Impl.java 生成的源文件中的 A 行和 B 行。

@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 _result;
        } finally {
          _cursor.close();
        }
      }
    }.getLiveData();
  }

viewmodel 中的这一行给你错误。您正在为空的房间数据库设置 mSimpleSQLiteQuery

mNameColumn = mRepository.getNameColumn(mSimpleSQLiteQuery);

您应该从视图模型中删除上面的行并修改 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

ViewModel 中的 mNameColumn LiveData 是在执行 ViewModel 构造函数时使用 null mSimpleSQLiteQuery 创建的。您在 getNameColumn 中进行了设置,但请注意,您的实时数据不知道这个新值。

因此 ShotDaoLiveData<List<Shot>> getNameColumn(SupportSQLiteQuery supportSQLiteQuery); 的实现收到 null SupportSQLiteQuery 导致崩溃。