使用Room,ViewModel和LiveData更改数据后重新加载RecyclerView [英] Reload RecyclerView after data change with Room, ViewModel and LiveData

查看:564
本文介绍了使用Room,ViewModel和LiveData更改数据后重新加载RecyclerView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图解决问题几天都没有成功.每当数据库(数据库室)中特定模型的记录发生更改时,我都希望更新recyclerView.我使用ViewModel处理模型数据,记录列表存储在LiveData中.

I am trying, without success, to solve a problem for days. I would like to update my recyclerView whenever the records of a particular model change in the Database (DB Room). I use ViewModel to handle the model data and the list of records are stored in LiveData.

数据库

@Database(entities = arrayOf(Additive::class), version = ElementDatabase.DB_VERSION, exportSchema = false)
    abstract class ElementDatabase() : RoomDatabase() {

        companion object {
            const val DB_NAME : String = "element_db"
            const val DB_VERSION : Int = 1

            fun get(appContext : Context) : ElementDatabase {
                return Room.databaseBuilder(appContext, ElementDatabase::class.java, DB_NAME).build()
            }
        }

        abstract fun additivesModels() : AdditiveDao

    }

模型

@Entity
class Additive {

    @PrimaryKey @ColumnInfo(name = "id")
    var number : String = ""
    var dangerousness : Int = 0
    var description : String = ""
    var names : String = ""
    var notes : String = ""
    var risks : String = ""
    var advice : String = ""
}

Dao

@Dao
interface AdditiveDao {

    @Query("SELECT * FROM Additive")
    fun getAllAdditives() : LiveData<List<Additive>>

    @Query("SELECT * FROM Additive WHERE id = :arg0")
    fun getAdditiveById(id : String) : Additive

    @Query("DELETE FROM Additive")
    fun deleteAll()

    @Insert(onConflict = REPLACE)
    fun insert(additive: Additive)

    @Update
    fun update(additive: Additive)

    @Delete
    fun delete(additive: Additive)
}

ViewModel

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

    private var elementDatabase : ElementDatabase
    private val additivesModels : LiveData<List<Additive>>

    init {
        this.elementDatabase = ElementDatabase.get(appContext = getApplication())
        this.additivesModels = this.elementDatabase.additivesModels().getAllAdditives()
    }

    fun getAdditivesList() : LiveData<List<Additive>> {
        return this.additivesModels
    }

    fun deleteItem(additive : Additive) {
        DeleteAsyncTask(this.elementDatabase).execute(additive)
    }

    private class DeleteAsyncTask internal constructor(private val db: ElementDatabase) : AsyncTask<Additive, Void, Void>() {

        override fun doInBackground(vararg params: Additive): Void? {
            db.additivesModels().delete(params[0])
            return null
        }

    }
}

片段

class AdditivesFragment : LifecycleFragment() {

    private var viewModel : AdditiveViewModel? = null
    private var adapter : AdditivesAdapter? = null

    companion object {
        fun newInstance() : AdditivesFragment {
            val f = AdditivesFragment()
            val args = Bundle()

            f.arguments = args
            return f
        }
    }

    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater?.inflate(R.layout.fragment_additives, container, false)
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        this.adapter = AdditivesAdapter(ArrayList<Additive>())
        this.additives_list.layoutManager = GridLayoutManager(this.context, 2, GridLayoutManager.VERTICAL, false)
        this.additives_list.adapter = this.adapter

        this.viewModel = ViewModelProviders.of(this).get(AdditiveViewModel::class.java)

        this.viewModel?.getAdditivesList()?.observe(this, Observer<List<Additive>> { additivesList ->
            if(additivesList != null) {
                this.adapter?.addItems(additivesList)
            }
        })
        super.onActivityCreated(savedInstanceState)
    }
}

现在,我的问题是为什么观察者只被调用一次(在片段的开头),然后又不被调用呢?如何使观察者不断聆听数据库中的更改(插入,更新,删除),以便可以立即更新我的recyclerView?非常感谢您的任何建议.

Now, my question is why is the observer called only once (at the start of the fragment) and then is not called back again? How can I keep the observer constantly listening to the changes in the DB (insert, update, delete) so that my recyclerView instantly can be updated? Thanks a lot for any suggestion.

推荐答案

这是您犯错的地方:

 this.viewModel = ViewModelProviders.of(this).get(AdditiveViewModel::class.java)

当您在fragment内部时正在传递this,这对于某些人来说是非常令人不安的,因为这不是语法错误,而是合乎逻辑的.您必须通过activity!!,它会像这样:

you are passing this while you are inside the fragment which is pretty disturbing for some people cause it is not a syntax error but logical. You have to pass activity!! instead, it will be like this:

this.viewModel = ViewModelProviders.of(activity!!).get(AdditiveViewModel::class.java)

这篇关于使用Room,ViewModel和LiveData更改数据后重新加载RecyclerView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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