Android LiveData和Room:getValue返回NULL [英] Android LiveData and Room: getValue returning NULL

查看:411
本文介绍了Android LiveData和Room:getValue返回NULL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用ROOM从数据库读取数据并返回LiveData时,getValue()方法将返回null.一段时间以来,我一直无法理解出了什么问题.您能协助解决这个问题吗?数据库中有数据,似乎更多是我如何使用LiveData对象的问题.

When reading data from DB using ROOM and returning LiveData, getValue() method returns null. I have been unable to understand what is going wrong for a while now. Can you please assist with this issue? There is data in the database, it seems like it is more of an issue of how I am using LiveData objects.

活动:

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

ViewModel:

ViewModel:

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:

@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对象,则将获取正确的数据:

If in my viewModel I change filter function to return a new LiveData object, correct data is being fetched:

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

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

But then in my Activity I need to create a new observer, as now data is provided by new instances of 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);
      }
    });
  }

这绝对是正确的方法:/

This is definetely now the right way of doing this :/

推荐答案

您应该查看MediatorLiveData而不是MutableLiveData,它可以使您从存储库中进行更改.

Rather than MutableLiveData you should look at MediatorLiveData which will allow you to propopgate the changes from the repository.

这看起来类似于以下内容,其中您将存储库数据作为数据源添加到mediatorLiveData.当您从存储库接收数据时,这将触发回调,然后您可以通过调用setValue从mediatorLiveData发出该数据.

This would look something like below where you add the repository data as a data source to the mediatorLiveData. This will then trigger a callback when you receive data from the repository, which you can then emit from the mediatorLiveData by calling setValue.

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

这篇关于Android LiveData和Room:getValue返回NULL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆