【问题标题】:Android LiveData and Room: getValue returning NULLAndroid LiveData 和 Room:getValue 返回 NULL
【发布时间】:2019-02-07 17:24:02
【问题描述】:

使用 ROOM 从 DB 读取数据并返回 LiveData 时,getValue() 方法返回 null。我已经有一段时间无法理解出了什么问题。你能帮忙解决这个问题吗?数据库中有数据,这似乎更像是我如何使用 LiveData 对象的问题。

活动:

public class ExercisesViewActivity extends AppCompatActivity implements View.OnClickListener {

  private ExerciseViewModel exerciseViewModel;
  private ExercisesAdapter recyclerViewerAdapter;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_exercises_view);

    Toolbar toolbar = findViewById(R.id.toolbar_exercise_view_activity);
    toolbar.setTitle("Exercises");
    setSupportActionBar(toolbar);

    ActionBar actionBar = getSupportActionBar();
    if (actionBar != null) {
      actionBar.setDisplayHomeAsUpEnabled(true);
      actionBar.setDisplayShowHomeEnabled(true);
    }

    RecyclerView recyclerView = findViewById(R.id.exercise_view_recycle_viewer);
    RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
    recyclerView.setLayoutManager(layoutManager);
    this.recyclerViewerAdapter = new ExercisesAdapter();
    recyclerView.setAdapter(recyclerViewerAdapter);

    this.exerciseViewModel = ViewModelProviders.of(this).get(ExerciseViewModel.class);
    this.exerciseViewModel.setFilters("", "");
//    this.exerciseViewModel.selectAll();
    this.exerciseViewModel.select().observe(this, exercises -> {
      if (exercises != null) {
        this.recyclerViewerAdapter.updateDataset(exercises);
      }
    });

    Button button = findViewById(R.id.test_button);
    button.setOnClickListener(this);
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
      case android.R.id.home:
        onBackPressed();
        break;
    }

    return true;
  }

  @Override
  public void onClick(View v) {
    this.exerciseViewModel.setFilters("", "");
//    this.exerciseViewModel.select().observe(this, exercises -> {
//      if (exercises != null) {
//        this.recyclerViewerAdapter.updateDataset(exercises);
//      }
//    });
  }
}

视图模型:

public class ExerciseViewModel extends AndroidViewModel {
  ExercisesRepository repository;
  MutableLiveData<List<Exercise>> data;

  public ExerciseViewModel(Application application) {
    super(application);
    this.data = new MutableLiveData<>();
    this.repository = new ExercisesRepository(application);
  }

  public void setFilters(String muscleGroups, String type) {
    LiveData<List<Exercise>> listLiveData = this.repository.filterSelect(muscleGroups, type);
    this.data.setValue(listLiveData.getValue());
  }

  public void selectAll() {
//    this.data.setValue(this.repository.selectAll().getValue());
  }

  public LiveData<List<Exercise>> select() {
    return data;
  }

  public void insert(Exercise exercise) {
    this.repository.insert(exercise);
  }
}

存储库:

public class ExercisesRepository {
  private ExerciseDao dao;

  public ExercisesRepository(Application context) {
    WorkoutRoomDatabase database = WorkoutRoomDatabase.getDb(context);
    this.dao = database.exerciseDao();
  }

  public LiveData<List<Exercise>> filterSelect(String muscleGroups, String type) {
    return this.dao.filterSelect("%" + muscleGroups + "%", "%" + type + "%");
  }

  public LiveData<List<Exercise>> selectAll() {
    return this.dao.selectAll();
  }

  public void insert(Exercise exercise) {
    new insertAsyncTask(this.dao).execute(exercise);
  }

  private static class insertAsyncTask extends AsyncTask<Exercise, Void, Void> {

    private ExerciseDao exerciseDao;

    insertAsyncTask(ExerciseDao  dao) {
      exerciseDao = dao;
    }

    @Override
    protected Void doInBackground(final Exercise... params) {
      exerciseDao.insert(params[0]);
      return null;
    }
  }
}

道:

@Dao
public interface ExerciseDao {
  @Query("SELECT * FROM exercises WHERE muscleGroups LIKE :muscleGroup AND type LIKE :type")
  LiveData<List<Exercise>> filterSelect(String muscleGroup, String type);
  @Query("SELECT * FROM exercises")
  LiveData<List<Exercise>> selectAll();
  @Insert
  void insert(Exercise exercise);
  @Update
  void update(Exercise exercise);
  @Delete
  void delete(Exercise exercise);
  @Query("DELETE FROM exercises")
  void deleteAll();
}

更新:

如果在我的 viewModel 中我更改过滤器函数以返回一个新的 LiveData 对象,则正在获取正确的数据:

  public LiveData<List<Exercise>> filterSelect(String muscleGroups, String type) {
    return this.dao.filterSelect("%" + muscleGroups + "%", "%" + type + "%");
  }

但是在我的活动中,我需要创建一个新的观察者,因为现在数据由 LiveData 的新实例提供:

 @Override
  public void onClick(View v) {
    this.exerciseViewModel.setFilters("Biceps", "weight");
    this.exerciseViewModel.select().observe(this, exercises -> {
      if (exercises != null) {
        this.recyclerViewerAdapter.updateDataset(exercises);
      }
    });
  }

现在这绝对是正确的做法:/

【问题讨论】:

    标签: android architecture


    【解决方案1】:

    您试图在 filterSelete 中使用空值获取类似搜索。 this.exerciseViewModel.setFilters("", "");。 这个过滤器基本上是一个问题。你不能像搜索一样做空。 对此,您可以使用loadAll 查询。

    @Query("SELECT * FROM exercises") LiveData<List<Exercise>> loadAll();

    编辑:

    public LiveData<List<Exercise>> filterSelect(String muscleGroups, String type) {
    
    if(muscleGroups == "" && type == "") {
     return this.dao.loadAll()
    
    }else {
    
    return this.dao.filterSelect("%" + muscleGroups + "%", "%" + type + "%");
    
    }
    

    希望,它会解决你的问题。

    【讨论】:

    • 感谢您的回答。不幸的是,这就是现在的问题。我已经测试了你的建议,它仍然有同样的问题。早些时候我返回了一个新的 LiveData 对象,它获取了正确的数据,但是我需要创建一个新的 observable,这不是正确的做法。
    • loadAll 函数返回空对象?
    • loadAll 返回 LiveData 对象,但这是一个新的 LiveData 对象。为了利用相同的 observable,我需要将其数据放入现有的 MutableLiveData。所以,我使用 liveData.getValue() 这就是返回 null。除非有一些我不知道的不同方法。
    • 为了使用相同的参考,你可以做可编辑的答案。
    【解决方案2】:

    您应该查看 MediatorLiveData 而不是 MutableLiveData,这将允许您从存储库中传播更改。

    如下所示,您将存储库数据作为数据源添加到 mediatorLiveData。这将在您从存储库接收数据时触发回调,然后您可以通过调用 setValue 从 mediatorLiveData 发出该回调。

    public class ExerciseViewModel extends AndroidViewModel {
        ExercisesRepository repository;
        MediatorLiveData<List<Exercise>> mediatorLiveData = new MediatorLiveData<>();
    
        public ExerciseViewModel(Application application) {
            super(application);
            this.repository = new ExercisesRepository(application);
        }
    
        public void setFilters(String muscleGroups, String type) {
            LiveData<List<Exercise>> repositoryLiveData = this.repository.filterSelect(muscleGroups, type);
            mediatorLiveData.addSource(repositoryLiveData, exercisList -> {
                mediatorLiveData.removeSource(repositoryLiveData);
                mediatorLiveData.setValue(exercisList);
            });
        }
    
        public LiveData<List<Exercise>> select() {
            return mediatorLiveData;
        }
    

    【讨论】:

    • 感谢克里斯。这实际上可行,因此我会将您的答案标记为正确。我实际上选择不使用 Mediator 和 Transformations。我将在另一个答案中解释。
    【解决方案3】:

    我设法通过使用 MediatorLiveData 和转换解决了这个问题。

    所以现在我的 ViewModel 构造函数如下所示:

    public ExerciseViewModel(Application application) {
        super(application);
        this.repository = new ExercisesRepository(application);
        this.filterMutableLiveData = new MutableLiveData<>();
    
        ExercisesFilter filter = new ExercisesFilter();
        filter.muscleGroup = "";
        filter.type = "";
        this.filterMutableLiveData.setValue(filter);
    
        LiveData<List<Exercise>> source = Transformations.switchMap(
            this.filterMutableLiveData, value -> repository.filterSelect(value.muscleGroup, value.type)
        );
    
        this.data.addSource(source, val -> this.data.setValue(val));
      }
    

    我已经添加了这个方法:

     public void setFilterMutableLiveData(String muscleGroups, String type) {
        ExercisesFilter filter1 = new ExercisesFilter();
        filter1.muscleGroup = muscleGroups;
        filter1.type = type;
        this.filterMutableLiveData.setValue(filter1);
      }
    

    使用这种方法,每次更新过滤器时,都会触发传递给 Transformations.switchMap 的函数以获取新数据。最后,新的 LiveData 对象被添加到 MediatorLiveData 对象,因此一个观察者可以用于所有来源。

    来源:https://github.com/googlesamples/android-sunflower/blob/99df6189af927b5cc477167923bbbd5a4ca1ece9/app/src/main/java/com/google/samples/apps/sunflower/viewmodels/PlantListViewModel.kt#L42

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-21
      • 2023-03-25
      相关资源
      最近更新 更多