繁体   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

当我尝试用房间数据库中的视图 model 更新我的 recyclerView 时,每个 id 都会编辑前一个,而不是它在 recyclerView 中的项目 id。 我使用 adapterposition 将数据从 (EditCartFragment) 中的 recyclerView 项目传递到单击按钮上的 (EditSingleItemFragment)。

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

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 文件

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)
                }
            }
    }
}

我正在尝试更新在 recyclerView 中查看的我的房间数据库列。

我将从一些可以帮助您解决问题的建议开始,您的代码将变得非常易于理解和执行。

  1. 将变量 myCartItems 从 Fragment 移动到 ViewModel ViewModel 是保存状态和您在 UI 上使用的所有数据的正确位置。

  2. 使用 LiveData观察 myCartItems 列表上的变化。 不要忘记保护您的财产,请遵循以下模式:

class MyViewModel: ViewModel() {

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

}
  1. 观察 fragment 上 myCartItems 的变化 当 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. 你在使用 RecyclerView 吗? 更喜欢始终使用 RecyclerView而不是 ListView 或 GridView,因为它的性能要好得多。

  2. 对于 Adapter 实现,总是更喜欢使用 ListAdapter ,它有一种更有效的方法来比较当前列表和新列表并更新它。 你可以按照这个例子:

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