LiveData未更新UI(使用ViewModel和房间数据库)



所以我使用LiveData和ViewModel来设置获取和插入数据的功能,并且我使用Room数据库来保存数据。

在我将数据插入数据库后,我的RecyclerView没有更新数据。

再循环适配器交易量kt

class RecyclerAdapterTransaksi(var context: Context, private val listener: (Transaksi) -> Unit) :
RecyclerView.Adapter<RecyclerAdapterTransaksi.TransaksiViewHolder>() {
private var listTransaksi = arrayListOf<Transaksi>()
fun setListTransaksi(listTransaksi: ArrayList<Transaksi>) {
this.listTransaksi = listTransaksi
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TransaksiViewHolder {
context = parent.context
val binding = ListItemBinding.inflate(LayoutInflater.from(context), parent, false)
return TransaksiViewHolder(binding)
}
override fun onBindViewHolder(holder: TransaksiViewHolder, position: Int) {
holder.bindItem(listTransaksi[position], listener)
}
override fun getItemCount(): Int = listTransaksi.size
class TransaksiViewHolder(private val binding: ListItemBinding) :
RecyclerView.ViewHolder(binding.root) {
@SuppressLint("SimpleDateFormat")
fun bindItem(transaksi: Transaksi, listener: (Transaksi) -> Unit) {
binding.textViewNamaTransaksi.text = transaksi.namaTransaksi
binding.textViewJmlTransaksi.text = transaksi.total.toString()
binding.textViewTglTransaksi.text = SimpleDateFormat("dd MMM yyyy").format(transaksi.tglTransaksi!!)
itemView.setOnClickListener {
listener(transaksi)
}
}
}
}

使用RecyclerView 显示数据库数据的片段

Pemasukkan Fragment.kt

class PemasukkanFragment : Fragment() {
private var _binding: FragmentPemasukkanBinding? = null
private val binding get() = _binding!!
private val viewModel: TransaksiViewModel by lazy {
val dataSource = UwangkuDatabase.getInstance(requireContext()).transactionDao
val factory = TransaksiViewModelFactory(dataSource)
ViewModelProvider(this, factory).get(TransaksiViewModel::class.java)
}

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
_binding = FragmentPemasukkanBinding.inflate(inflater, container, false)
binding.fabPemasukkan.setOnClickListener {
val intent = Intent(requireContext(), TambahDataActivity::class.java)
intent.putExtra(Constant.TIPE_TRANSAKSI, Constant.PEMASUKKAN)
intent.putExtra(Constant.TIPE_AKSI, Constant.AKSI_TAMBAH)
startActivity(intent)
}
getDataPemasukkan()
return binding.root
}

private fun getDataPemasukkan() {
binding.recyclerViewPemasukan.setHasFixedSize(true)
binding.recyclerViewPemasukan.layoutManager = LinearLayoutManager(requireContext())
val adapter = RecyclerAdapterTransaksi(requireContext()) {
//action when item clicked
showKonfirmasiEdit(it)
}
binding.recyclerViewPemasukan.adapter = adapter
viewModel.getData(Date(), Constant.PEMASUKKAN)
viewModel.dataTransaksi.observe(viewLifecycleOwner, Observer {
adapter.setListTransaksi(it as ArrayList<Transaksi>)
})
}
private fun showKonfirmasiEdit(transaksi: Transaksi){
val intent = Intent(requireContext(),TambahDataActivity::class.java)
val builder = AlertDialog.Builder(requireContext())
.setMessage(R.string.edit_message)
.setPositiveButton(R.string.edit){_,_ ->
intent.putExtra(Constant.DATA_PEMASUKKAN, transaksi)
intent.putExtra(Constant.TIPE_TRANSAKSI, Constant.PEMASUKKAN)
intent.putExtra(Constant.TIPE_AKSI, Constant.AKSI_EDIT)
startActivity(intent)
}
.setNegativeButton(R.string.batal){dialog, _ ->
dialog.cancel()
}
builder.show()
}
}

使用LiveData 的ViewModel类

TransaksiViewModel.kt

class TransaksiViewModel(private val dao: TransaksiDao) : ViewModel() {
private var _dataTransaksi = MutableLiveData<List<Transaksi>>()
val dataTransaksi: LiveData<List<Transaksi>>
get() = _dataTransaksi
private suspend fun getDataTransaksi(tgl : Date, tipe : String) = withContext(Dispatchers.IO) {
dao.getData(tgl, tipe)
}
fun getData(tgl : Date, tipe : String) {
viewModelScope.launch {
_dataTransaksi.postValue(getDataTransaksi(tgl, tipe))
}
}
fun inserDataTransaksi(transaksi: Transaksi) {
viewModelScope.launch {
insertTransaksi(transaksi)
}
}
private suspend fun insertTransaksi(transaksi: Transaksi){
withContext(Dispatchers.IO) {
dao.insertDataTransaksi(transaksi)
}
}
fun updateDataTransaksi(transaksi: Transaksi){
viewModelScope.launch {
updateTransaksi(transaksi)
}
}
private suspend fun updateTransaksi(transaksi: Transaksi){
withContext(Dispatchers.IO){
dao.updateDataTransaksi(transaksi)
}
}
}

DAO

TransakiDao.kt

@Dao
interface TransaksiDao {
@Insert
fun insertDataTransaksi(transaksi: Transaksi)
@Query("SELECT * FROM transaksi WHERE datetime(tanggal/1000,'unixepoch','start of month') = datetime(:tgl/1000,'unixepoch','start of month') AND jenis = :tipe ORDER BY id DESC")
fun getData(tgl : Date, tipe : String): List<Transaksi>
@Update
fun updateDataTransaksi(transaksi: Transaksi)
}

将数据插入数据库的活动

TambahDataActivity.kt

class TambahDataActivity : AppCompatActivity() {
private lateinit var binding: ActivityTambahDataBinding
private val viewModel: TransaksiViewModel by lazy {
val dataSource = UwangkuDatabase.getInstance(this).transactionDao
val factory = TransaksiViewModelFactory(dataSource)
ViewModelProvider(this, factory).get(TransaksiViewModel::class.java)
}
@SuppressLint("SimpleDateFormat")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityTambahDataBinding.inflate(layoutInflater)
setContentView(binding.root)
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
val getAksi = intent.getStringExtra(Constant.TIPE_AKSI)
val getJenisTransaksi = intent.getStringExtra(Constant.TIPE_TRANSAKSI)
if(getJenisTransaksi == Constant.PEMASUKKAN){
val dataPemasukan = intent.getParcelableExtra<Transaksi>(Constant.DATA_PEMASUKKAN)
if(dataPemasukan != null){
getDataFromIntent(dataPemasukan)
}
} else if(getJenisTransaksi == Constant.PENGELUARAN){
val dataPengeluaran = intent.getParcelableExtra<Transaksi>(Constant.DATA_PENGELUARAN)
if(dataPengeluaran != null){
getDataFromIntent(dataPengeluaran)
}
}
if(getAksi == Constant.AKSI_EDIT){
binding.buttonTambah.text = getString(R.string.edit)
title = getString(R.string.edit_data)
}
binding.textViewTanggal.setOnClickListener { showDatePickerDialog() }
binding.buttonTambah.setOnClickListener {
if(getAksi == Constant.AKSI_TAMBAH){
insertData()
}else if(getAksi == Constant.AKSI_EDIT){
updateData()
}
}
}
@SuppressLint("SimpleDateFormat")
private fun insertData(){
val namaTransaksi = binding.editTextKeterangan.text
val jumlahTransaki = binding.editTextJumlah.text
val getJenisTransaksi = intent.getStringExtra(Constant.TIPE_TRANSAKSI)
val jenisTransaksi = if (getJenisTransaksi == Constant.PEMASUKKAN) {
Constant.PEMASUKKAN
} else {
Constant.PENGELUARAN
}
val tanggalTransaksi =
SimpleDateFormat("dd-MM-yyyy").parse(binding.textViewTanggal.text.toString())
val transaksi = Transaksi(
0,
namaTransaksi.toString(),
jenisTransaksi,
jumlahTransaki.toString().toInt(),
tanggalTransaksi
)
viewModel.inserDataTransaksi(transaksi).apply { finish() }
}
@SuppressLint("SimpleDateFormat")
private fun updateData(){
val namaTransaksi = binding.editTextKeterangan.text
val jumlahTransaki = binding.editTextJumlah.text
val getJenisTransaksi = intent.getStringExtra(Constant.TIPE_TRANSAKSI)
val jenisTransaksi = if (getJenisTransaksi == Constant.PEMASUKKAN) {
Constant.PEMASUKKAN
} else {
Constant.PENGELUARAN
}
val tanggalTransaksi =
SimpleDateFormat("dd-MM-yyyy").parse(binding.textViewTanggal.text.toString())
if(getJenisTransaksi == Constant.PEMASUKKAN){
val dataPemasukan = intent.getParcelableExtra<Transaksi>(Constant.DATA_PEMASUKKAN)!!
val transaksi = Transaksi(dataPemasukan.id,
namaTransaksi.toString(),
jenisTransaksi,
jumlahTransaki.toString().toInt(),
tanggalTransaksi
)
viewModel.updateDataTransaksi(transaksi)
} else if(getJenisTransaksi == Constant.PENGELUARAN){
val dataPengeluaran = intent.getParcelableExtra<Transaksi>(Constant.DATA_PENGELUARAN)!!
val transaksi = Transaksi(dataPengeluaran.id,
namaTransaksi.toString(),
jenisTransaksi,
jumlahTransaki.toString().toInt(),
tanggalTransaksi
)
viewModel.updateDataTransaksi(transaksi)
}
}
@SuppressLint("SimpleDateFormat")
private fun getDataFromIntent(data : Transaksi?){
if(data != null){
binding.editTextKeterangan.setText(data.namaTransaksi)
binding.editTextJumlah.setText(data.total.toString())
binding.textViewTanggal.text = SimpleDateFormat("dd-MM-yyyy").format(data.tglTransaksi!!)
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> finish()
}
return true
}
@SuppressLint("SetTextI18n")
private fun showDatePickerDialog() {
val calendar = Calendar.getInstance()
val tahun = calendar.get(Calendar.YEAR)
val bulan = calendar.get(Calendar.MONTH)
val hari = calendar.get(Calendar.DAY_OF_MONTH)
val datePicker = DatePickerDialog(
this,
DatePickerDialog.OnDateSetListener { view, _year, monthOfYear, dayOfMonth ->
binding.textViewTanggal.text = "$dayOfMonth-${monthOfYear + 1}-$_year "
},
tahun,
bulan,
hari
)
datePicker.show()
}

我不知道这是怎么回事,我被困了两天。

提前谢谢。

如果使用的是singleton实现,则需要检查数据库实例。我也遇到了同样的问题,然后我在代码中发现了错误,我的解决方案从下面的代码""改为"singleton">

companion object {
private var INSTANCE: PokemonDatabase? = null
fun getDatabase(context: Context): PokemonDatabase {
return INSTANCE ?: Room.databaseBuilder(
context.applicationContext,
PokemonDatabase::class.java,
"pokemon_db"
).build()
}

`

至低于代码

companion object {
@Volatile
private var INSTANCE: PokemonDatabase? = null
fun getDatabase(context: Context): PokemonDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
PokemonDatabase::class.java,
"pokemon_db"
).build()
INSTANCE = instance
instance//this return instance
}
}
}

最新更新