首页 > 解决方案 > 使用 ViewModel 和数据绑定显示 Room 数据库中的数据时出现问题

问题描述

我正在构建一个 android 应用程序,我在 Detailfragment 的数据库中添加产品并在主片段中显示它们:这是 Product 类:

@Parcelize
 @Entity(tableName = "product_table")

data class Product (
@ColumnInfo(name = "name")
var name:String = "product",
):Parcelable{@PrimaryKey(autoGenerate = true)
var id:Long = 0L}

这是我正在使用的 ProductViewModel

    class ProductViewModel(val database: ProductDatabaseDao) : ViewModel() {
    val products = database.getAllProducts()
    val productsString = products.value?.get(0)?.name
    private var _navigateToProductsList = MutableLiveData<Boolean>()

    val navigateToProductsList : LiveData<Boolean>
    get() = _navigateToProductsList

    private suspend fun insert(product: Product) {
        database.insert(product)
    }

    fun onAddProduct(){
        viewModelScope.launch {
            val product = Product()
            product.name = "toy"
            insert(product)
        }
        _navigateToProductsList.value = true
    }
    fun doneNavigation(){
        _navigateToProductsList.value = false
    }
}

这是 ProductDetailFragment:

    class ProductDetailFragment : Fragment() {
    private val productViewModel: ProductViewModel by activityViewModels {
        ProductViewModelFactory(
            getDatabase()
        )
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        // Inflate the layout for this fragment
    val binding = DataBindingUtil.inflate<FragmentProductDetailBinding>(

            inflater,
            R.layout.fragment_product_detail,
            container,
            false
        )

binding.lifecycleOwner = this
        binding.productViewModel = productViewModel
    productViewModel.navigateToProductsList.observe(viewLifecycleOwner, Observer {

            if (it == true) {
                this.findNavController()
                    .navigate(ProductDetailFragmentDirections.actionProductDetailFragmentToProductsListFragment())
                // Reset state to make sure we only navigate once, even if the device
                // has a configuration change
                productViewModel.doneNavigation()
            }

        })
return binding.root
    }

    fun getDatabase(): ProductDatabaseDao {
        val application = requireNotNull(this.activity).application
        val dataSource = ProductDatabase.getInstance(application).productDatabaseDao
        return dataSource
    }
}

这是product_detail_fragment

    <layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    <data>
        <variable
            name="productViewModel"
            type="com.github.mariemmezghani.inventory.viewModel.ProductViewModel" />
    </data>
<androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <EditText
            android:id="@+id/product_name"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:layout_marginTop="32dp"
            android:layout_marginEnd="16dp"
            android:ems="10"
            android:inputType="textPersonName"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <Button
            android:id="@+id/save_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:layout_marginTop="32dp"
            android:layout_marginEnd="16dp"
            android:background="@drawable/round_button"
            android:text="@string/save_button"
            android:textColor="@color/white"
            android:onClick="@{()->productViewModel.onAddProduct()}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/product_name" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

在这里,我在 save_Button 中调用 productViewmodel.onAddProduct()

这是 products_list_fragment

     <?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <!-- Data to make available to the XML via data binding. In this case,
         the whole ViewModel, so that we can access the LiveData,
         click handlers, and state variables. -->
    <data>
        <variable
            name="viewModel"
            type="com.github.mariemmezghani.inventory.viewModel.ProductViewModel" />
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
android:layout_height="match_parent"

    tools:context=".ProductsListFragment">

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/add_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="32dp"
        android:clickable="true"
        app:backgroundTint="@color/color_primary"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:srcCompat="@android:drawable/ic_input_add" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="32dp"
        android:layout_marginEnd="16dp"
        android:text="@{viewModel.productsString}"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.495"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

在实现recyclerView显示用户添加的产品之前,我想测试一下产品是否正确添加到数据库中,所以我只是添加了一个产品并给它起一个名字“玩具”,并尝试在TextView中显示它此 product_list_fragment。

我不知道为什么这不起作用,当我按下save_Button

谢谢您的帮助

标签: androidkotlinandroid-roomviewmodel

解决方案


您的视图模型可能会在数据库操作完成之前被破坏,因此您可以尝试以下操作

    fun onAddProduct(){
        viewModelScope.launch {
            val product = Product()
            product.name = "toy"
            insert(product)
            _navigateToProductsList.postValue(true)
        }
    }

推荐阅读