简体   繁体   English

无法使用房间数据库中的视图 model 更新我的 recyclerView,每个项目都会编辑前一个,而不是它在 recyclerView 中的项目 ID

[英]Can't update my recyclerView with view model in room database, every item edits the previous one, not its item id in recyclerView

When i tried to update my recyclerView with view model in room database every id edits the previous one, not its item id in recyclerView.当我尝试用房间数据库中的视图 model 更新我的 recyclerView 时,每个 id 都会编辑前一个,而不是它在 recyclerView 中的项目 id。 I used adapterposition for passing the data from recyclerView item in (EditCartFragment) to (EditSingleItemFragment) on button Clicked.我使用 adapterposition 将数据从 (EditCartFragment) 中的 recyclerView 项目传递到单击按钮上的 (EditSingleItemFragment)。

EditCartFragment.kt EditCartFragment.kt

class EditCartFragment : Fragment(), CommunicatorEdit{
    //Then MyCart data is ignored and we took our data from local database
    private val myCartItems = ArrayList<MyCartItemsDatabase>()
    private val myCartEditAdapter = MyCartEditAdapter(myCartItems, this)
    //Our ViewModel instance
    private lateinit var cartViewModel: CartViewModel
    // TODO: Rename and change types of parameters
    private var param1: String? = null
    private var param2: String? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {
            param1 = it.getString(ARG_PARAM1)
            param2 = it.getString(ARG_PARAM2)
        }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        myCartDynamic.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
        myCartDynamic.adapter = myCartEditAdapter
        //addData()
        //Setting my view model and my dynamic list
        cartViewModel = ViewModelProvider(this)[CartViewModel::class.java]
        cartViewModel.readAllData.observe(viewLifecycleOwner) { cart ->
            myCartEditAdapter.setData(cart)
        }
    }

    override fun passData(position: Int, title: String, image: Bitmap, price: Double, priceI: Double, num: Int, des: String) {
        val bundle = Bundle()
        bundle.putInt("edit_pos", position)
        bundle.putString("edit_name", title)
        bundle.putString("edit_image", getImageUri(requireContext(), image).toString())
        bundle.putDouble("edit_price", price)
        bundle.putDouble("edit_priceI", priceI)
        bundle.putInt("edit_num", num)
        bundle.putString("edit_des", des)

        val transaction = this.parentFragmentManager.beginTransaction()
        val editSingleItemFragment = EditSingleItemFragment()
        editSingleItemFragment.arguments = bundle

        transaction.replace(R.id.fragment_container, editSingleItemFragment)
        transaction.addToBackStack("editSI_fragment").setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
        transaction.commit()
    }

    //Converting bitmap image to URL
    private fun getImageUri(inContext: Context, inImage: Bitmap): Uri? {
        val bytes = ByteArrayOutputStream()
        inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes)
        val path = MediaStore.Images.Media.insertImage(
            inContext.contentResolver,
            inImage,
            "Title",
            null
        )
        return Uri.parse(path)
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_edit_cart, container, false)
    }

    companion object {
        /**
         * Use this factory method to create a new instance of
         * this fragment using the provided parameters.
         *
         * @param param1 Parameter 1.
         * @param param2 Parameter 2.
         * @return A new instance of fragment MyCartFragment.
         */
        // TODO: Rename and change types and number of parameters
        @JvmStatic
        fun newInstance(param1: String, param2: String) =
            EditCartFragment().apply {
                arguments = Bundle().apply {
                    putString(ARG_PARAM1, param1)
                    putString(ARG_PARAM2, param2)
                }
            }
    }
}

CartEditAdapter.kt CartEditAdapter.kt

class CartEditAdapter(private var cartItems: List<CartItemsDatabase>, private val listener: CommunicatorEdit):
    RecyclerView.Adapter<CartEditAdapter.MyViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val cartView = LayoutInflater.from(parent.context).inflate(R.layout.edit_cart_items, parent, false)
        return MyViewHolder(cartView)
    }

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val newCart = cartItems[position]
        holder.cartedImg.load(newCart.cartImage){
            crossfade(true)
            transformations(CircleCropTransformation())
            placeholder(R.drawable.ic_launcher_foreground)
        }
        holder.cartedTitle.text = newCart.cartTitle.toString()
        holder.cartedItemNum.text = newCart.cartNum.toString()
        holder.cartedLPriceValue.text = newCart.cartPriceL.toString()
        holder.cartedIPriceValue.text = newCart.cartPriceI.toString()
        holder.cartedDes.text = newCart.cartDes.toString()
    }

    //Setting data from database
    fun setData(myCartComingItem: List<CartItemsDatabase>){
        this.cartItems = myCartComingItem
        notifyDataSetChanged()
    }

    override fun getItemCount(): Int {
        return cartItems.size
    }

    inner class MyViewHolder constructor(itemView: View): RecyclerView.ViewHolder(itemView), View.OnClickListener{

        init {
            //Setting decrease items
            itemView.editMyItem.setOnClickListener(this)
        }

        override fun onClick(v: View?) {
            val position = adapterPosition
            val image = cartItems[adapterPosition].cartImage
            val name =  cartItems[adapterPosition].cartTitle
            val price = cartItems[adapterPosition].cartPriceL
            val priceI = cartItems[adapterPosition].cartPriceI
            val num = cartItems[adapterPosition].cartNum
            val des = cartItems[adapterPosition].cartDes
            if (position != RecyclerView.NO_POSITION) {
                listener.passData(position,name!!, image!!, price!!, priceI!!, num!!, des!!)
            }
        }

        val cartedImg: ShapeableImageView = itemView.myCartedImg
        val cartedTitle: TextView = itemView.myCartedTitle
        val cartedItemNum: TextView = itemView.myCartItemNum
        val cartedLPriceValue: TextView = itemView.localPriceCart
        val cartedIPriceValue: TextView = itemView.localPriceCartA
        val cartedDes: TextView = itemView.myCartedDes
    }
}

EditSingleItemFragment.kt EditSingleItemFragment.kt 文件

class EditSingleItemFragment : Fragment() {
    //First, we have to initialize our view model
    private lateinit var cartViewModel: CartViewModel
    private var editPos: Int?= null
    private var editTitle: String = ""
    private var editImage: String = ""
    private var editPriceL: Double = 0.0
    private var editPriceI: Double = 0.0
    private var editNum: Int = 0
    private var editDes: String = ""
    // TODO: Rename and change types of parameters
    private var param1: String? = null
    private var param2: String? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {
            param1 = it.getString(ARG_PARAM1)
            param2 = it.getString(ARG_PARAM2)
        }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        editPos = arguments?.getInt("edit_pos")
        editTitle = arguments?.getString("edit_name").toString()
        editImage = requireArguments().getString("edit_image").toString()
        editPriceL = requireArguments().getDouble("edit_price")
        editPriceI = requireArguments().getDouble("edit_priceI")
        editNum = requireArguments().getInt("edit_num")
        editDes = arguments?.getString("edit_des").toString()

        editSTitle.text = editTitle
        editSImg.load(editImage){
            crossfade(true)
            transformations(CircleCropTransformation())
            placeholder(R.drawable.ic_launcher_foreground)
        }
        editSLPrice.text = editPriceL.toString()
        editSIPrice.text = editPriceI.toString()
        editSNum.text = editNum.toString()
        editSDes.text = editDes
        //Edit our items number
        incDecNum()
        //View Model Calling
        cartViewModel = ViewModelProvider(this)[CartViewModel::class.java]
        //Update Cart listener
        editSUpdate.setOnClickListener {
            lifecycleScope.launch {
                updateDatabase()
                Toast.makeText(context, "Item is updated", Toast.LENGTH_SHORT).show()
            }
        }
    }
    //Add data to database
    private suspend fun updateDatabase(){
        val cartedTitle = editSTitle.text.toString()
        val cartedImage = getBitmap(editImage)
        val cartedPrice = editSLPrice.text.toString().toDouble()
        val cartedPriceI = editSIPrice.text.toString().toDouble()
        val cartedItemNum = editSNum.text.toString().toInt()
        val cartedDes = editSDes.text.toString()
        val item = MyCartItemsDatabase(editPos!!, cartedTitle, cartedImage,
            cartedPrice, cartedPriceI, cartedItemNum, cartedDes)
        cartViewModel.updateCart(item)
    }
    //Converting image url to bitMap
    private suspend fun getBitmap(img: String): Bitmap {
        val loading = ImageLoader(requireContext())
        val request = ImageRequest.Builder(requireContext())
            .data(img).build()
        val result: Drawable = (loading.execute(request) as SuccessResult).drawable
        return (result as BitmapDrawable).bitmap
    }

    //Increase or decrease items' number
    private fun incDecNum(){
        //Initializing the price value
        val myPrice = editSLPrice.text.toString().toDouble()
        //Initializing the incDec value
        var numberOfItems = editSNum.text.toString().toInt()
        editSDec.setOnClickListener {
            if (numberOfItems > 1){
                numberOfItems -= 1
                val newVal = numberOfItems.toString()
                editSNum.text = newVal
                val price = myPrice*numberOfItems
                editSIPrice.text = price.toString()
            }
        }
        editSInc.setOnClickListener {
            numberOfItems += 1
            val newVal = numberOfItems.toString()
            editSNum.text = newVal
            val price = myPrice*numberOfItems
            editSIPrice.text = price.toString()
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_edit_single_item, container, false)
    }

    companion object {
        /**
         * Use this factory method to create a new instance of
         * this fragment using the provided parameters.
         *
         * @param param1 Parameter 1.
         * @param param2 Parameter 2.
         * @return A new instance of fragment EditSingleItemFragment.
         */
        // TODO: Rename and change types and number of parameters
        @JvmStatic
        fun newInstance(param1: String, param2: String) =
            EditSingleItemFragment().apply {
                arguments = Bundle().apply {
                    putString(ARG_PARAM1, param1)
                    putString(ARG_PARAM2, param2)
                }
            }
    }
}

I'm trying to update my room database columns viewed in recyclerView.我正在尝试更新在 recyclerView 中查看的我的房间数据库列。

I'll start with some suggestions that will help you with your problem and your code will become very clear to understand and performative.我将从一些可以帮助您解决问题的建议开始,您的代码将变得非常易于理解和执行。

  1. Move the variable myCartItems from the Fragment to ViewModel .将变量 myCartItems 从 Fragment 移动到 ViewModel The ViewModel is the right place to keep the status and all data that you use on your UI. ViewModel 是保存状态和您在 UI 上使用的所有数据的正确位置。

  2. Use LiveData to observe the changes on your myCartItems list.使用 LiveData观察 myCartItems 列表上的变化。 Do not forget to protect your property, follow this pattern:不要忘记保护您的财产,请遵循以下模式:

class MyViewModel: ViewModel() {

    private val _myCartItems = MutableLiveData<List<MyCartItemsDatabase>>(emptyList())
    val myCartItems: LiveData<List<MyCartItemsDatabase>>
        get() = _myCartItems

}
  1. Observe changes on myCartItems on your fragment .观察 fragment 上 myCartItems 的变化 When myCartItems update on ViewModel, the observer will be notified and then you can send the updated list that you receive on your observer to the adapter当 myCartItems 在 ViewModel 上更新时,观察者将收到通知,然后您可以将您在观察者上收到的更新列表发送到适配器
class MyFragment: Fragment()  {

    private val viewModel: MyViewModel by viewModel()

    private lateinit var adapter: MyAdapter

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        // set the adapter to your recycler view
        // observe changes of your live data
        viewModel.myCartItems.observe(viewLifecycleOwner) { myCartItems ->
            // You will send the myCartItems that you receive to your adapter here
        }
    }
}
  1. Are you using RecyclerView?你在使用 RecyclerView 吗? Prefer always to use RecyclerView instead ListView or GridView, because it's so much more performative.更喜欢始终使用 RecyclerView而不是 ListView 或 GridView,因为它的性能要好得多。

  2. For the Adapter implementation, always prefer to use ListAdapter too, that have a more efficient way to compare the current list with the new list and update it.对于 Adapter 实现,总是更喜欢使用 ListAdapter ,它有一种更有效的方法来比较当前列表和新列表并更新它。 You can follow this example:你可以按照这个例子:

abstract class MyAdapter: ListAdapter<MyCartItemsDatabase, MyAdapter.MyAdapterViewHolder>(DIFF_CALLBACK) {
   
     // ...

    class MyAdapterViewHolder(
        private val binding: ItemSimplePosterBinding
    ): RecyclerView.ViewHolder(binding.root) {
     // ...
     }

    companion object {
        private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<MyCartItemsDatabase>() {
            override fun areItemsTheSame(oldItem: MyCartItemsDatabase, newItem: MyCartItemsDatabase): Boolean {
                // need a unique identifier to have sure they are the same item. could be a comparison of ids. In this case, that is just a list of strings just compare like this below
                return oldItem.id == newItem.id
            }

            override fun areContentsTheSame(oldItem: MyCartItemsDatabase, newItem: MyCartItemsDatabase): Boolean {
                // compare the objects
                return oldItem.items == newItem.items
            }

        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM