【问题标题】:how to pass a parameter to my Word Dao for query using View Model and Live Data?如何使用 View Model 和 Live Data 将参数传递给我的 Word Dao 进行查询?
【发布时间】:2021-06-27 09:14:50
【问题描述】:

更新:如何使用 ViewModelFactory 以及是否有必要使用它来传递我们的参数?有什么好处?这会打破实时数据的概念吗?

我想将参数发送到我房间数据库的单词 Dao 以进行查询,但就我而言,我不知道如何传递该参数。所以让我们从代码开始...... WordDao.kt

@Dao
interface WordDao {

    @Insert
    fun insert(word: Word)

    @Update
    fun update(word: Word)

    @Delete
    fun delete(word: Word)

    @Query("delete from En_Fa")
    fun deleteAllNotes()

    @Query("SELECT * FROM En_Fa ORDER BY id ASC")
    fun getAllNotes(): LiveData<List<Word>>

    @Query("Select * From En_Fa WHERE date == :today ")
    fun getTodayWords(today: String): LiveData<List<Word>>
}

WordRepository.kt

class WordRepository(private val wordDao: WordDao, today: String) {

    val readAllData: LiveData<List<Word>> = wordDao.getAllNotes()
    val readToday: LiveData<List<Word>> = wordDao.getTodayWords(today)


    fun addWord(word: Word) {
        wordDao.insert(word)
    }
}

WordViewModel.kt

class WordViewModel(application: Application): AndroidViewModel(application) {

    val readAllData2: LiveData<List<Word>>

    private val repository: WordRepository

    init {

        val wordDao = WordDatabase.getInstance(application).wordDao()

        repository = WordRepository(wordDao, today)
        readAllData2 = repository.readToday

    }

    fun addWord(word: Word){
        viewModelScope.launch(Dispatchers.IO){
            repository.addWord(word)
        }
    }

}

这是在我的片段中创建此 wordview 模型类的对象的代码行

private val mWordViewModel: WordViewModel by viewModels()

那么如何将我的(今天)变量从我的片段传递到我的 WordViewModel 类

【问题讨论】:

  • 你必须使用 viewmodelFactory 来为你的 viewmodel 提供在初始化状态下的今天的值
  • 看看this
  • 请查看answer,它显示了如何使用 ViewModelFactory 将其他变量(在您的情况下为 today)传递给 viewModel 的构造函数。

标签: android kotlin android-room android-livedata android-viewmodel


【解决方案1】:

我想你正在寻找这个:


@Dao
interface WordDao {
// ...
    @Query("Select * From En_Fa WHERE date == :today ")
    fun getTodayWords2(today: String): <List<Word>
}

然后在仓库中:

class WordRepository{
  // ... ...
  var mutableWords: MutableLiveData<List<Word>> = MutableLiveData()

  fun getWords(today: String): List<Word> {  // WARNING! run this in background thread else it will crash
    return wordDao.getTodayWords2(today)
  }

  fun getWordsAsync(today: String) {
   Executors.newSingleThreadExecutor().execute { 
          val words = getWords(today)
          liveWords.postValue(words)   // <-- just doing this will trigger the observer and do next thing, such as, updating ui
        }
  }
}

然后在你的 viewModel 中:

class WordViewModel(application: Application): AndroidViewModel(application) {
  // ... ...

  val liveWords: LiveData<List<Word>> = repository.mutableWords

  fun getWordsAsync(today: String) {
    repository.getWordsAsync(today)
  }
}

最后在你的活动/片段中:

fun viewModelDemo() {
  mWordViewModel.liveWords.observe(this, Observer{
    // todo: update the ui, eg
    someTextView.text = it.toString()    // <-- here you get the output
   })


   someButton.setOnClickListener{
// here you give the input
  mWordViewModel.getWordsAsync(today)  // get `today` from date picker or something    
   }
}

编辑

所以你有一个带有适配器的 recyclerView。当数据集发生变化时,您调用notifyDataSetChanged。假设,适配器如下所示:

class MyAdapter: RecyclerView.Adapter<ViewHolder> {
  private var words: List<Word> = ArrayList() // initially points to an empty list

  override fun getCount() { return words.size }
  // ... ... other methods

  // public method:
  fun submitList(words1: List<Word>) {
    this.words = words1  // so now it points to the submitted list
    this.notifyDataSetChanged()  // this tells recyclerView to update itself
  }  

}

然后在您的活动或片段中:

private lateinit var myAdapter: MyAdapter

override fun onCreate() {  // or onViewCreated if using fragment
  // ... ... some codes
  this.myAdapter = MyAdapter()
  binding.recyclerView.adapter = myAdapter

  viewModelDemo()
}

fun viewModelDemo() {
  mWordViewModel.liveWords.observe(this, Observer{
    // todo: update the ui, eg
    myAdapter.submitList(it)    // <----- Here you call the submitList method

    // <-- here you get the output
   })
  // --- ---
}

我希望这行得通。

【讨论】:

  • 所以这些天我一直在做一些事情,直到现在我回到我的代码并尝试了你的代码。它起作用了,但并不安静。我是实时数据的新手,我认为您的代码打破了实时数据的概念。当我转到我的仪表板片段时,它显示了我的数据库,但是当我向它添加一个单词时,直到我更改片段并再次返回时才显示它,在此之前,回收器视图立即更新自身,当我添加一个这个词表明了这一点
  • 你打电话给adapter.notifyDataSetChanged()了吗?
  • 我应该在哪里使用它?你能在你的答案中显示吗?
  • 我认为问题在于可变的实时数据。我搜索了其他人也遇到了这个问题。但是我们设置了 lifeCycleOwner!
  • 你好。我已经编辑了我的答案并根据要求添加了一些代码。请检查我的答案的底部,
【解决方案2】:

如果我正确地回答了你的问题, 首先,您需要创建一个函数,该函数将返回要观察的 liveData 对象,然后您需要使用 ViewModelProviders 在片段中为您提供 ViewModel 的对象。

mWordViewModel: WordViewModel = ViewModelProvider(this/getActivity()).get(WordViewModel::class.java)
mWordViewModel.getLiveDataFunction().observe(this/lifeCycleOwner, {
    process result/response here
}

然后简单地使用。

mWordViewModel.addWord(today)

【讨论】:

  • 这将在每次屏幕旋转时完成
  • @RahulRawat 如果重新创建活动,它会收到第一个活动创建的相同 MyViewModel 实例。所有者活动完成后,框架调用 ViewModel 对象的 onCleared() 方法,以便它可以清理资源。看到这个developer.android.com/topic/libraries/architecture/…
  • 我知道。看起来 Morteza 今天需要在创建 ViewModel 时调用一次 addWord,这就是为什么将问题添加到 init 中的原因
  • @SRBBans 我无法使用您的第一行代码,它显示错误“未解决的参考”。
  • @RahulRawat 我想在不破坏实时数据概念的情况下传递参数。
猜你喜欢
  • 2022-10-18
  • 1970-01-01
  • 1970-01-01
  • 2017-03-08
  • 2012-08-05
  • 1970-01-01
相关资源
最近更新 更多