当我将产品添加到购物车时,它什么也不显示

问题描述 投票:0回答:1

在我的 MenuFragment 中,我显示可以添加到购物车的产品,当我单击日志中的任何产品时,我看到该产品已添加到列表中并且列表已更新,但是当我转到 CartFragment 时,没有显示任何内容,在日志中我看到观察者观察到一个空列表并将其传递给适配器。

package com.example.restauratio.cart

import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.restauratio.R
import com.example.restauratio.databinding.FragmentCartBinding
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class CartFragment : Fragment() {

    private val cartViewModel: CartViewModel by viewModels()

    private var _binding: FragmentCartBinding? = null
    private val binding get() = _binding!!

    private lateinit var cartAdapter: CartAdapter

    private val actionCartToPop = R.id.action_cartFragment_pop

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentCartBinding.inflate(inflater, container, false)
        return binding.root
    }

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

        cartAdapter = CartAdapter(cartViewModel)

        binding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
        binding.recyclerView.adapter = cartAdapter

        cartViewModel.cartItems.observe(viewLifecycleOwner) { cartItems ->
            Log.d("CartFragment", "Observed cart items: $cartItems")
            cartAdapter.setCartItems(cartItems)
        }

        binding.imageView4.setOnClickListener {
            findNavController().navigate(actionCartToPop)
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}
package com.example.restauratio.cart

import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.example.restauratio.menu.DishModel
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject

@HiltViewModel
class CartViewModel @Inject constructor() : ViewModel() {

    private val _cartItems = MutableLiveData<List<DishModel>>()
    val cartItems: LiveData<List<DishModel>> get() = _cartItems

    fun addToCart(dish: DishModel) {
        Log.d("CartViewModel", "Adding to cart: $dish")
        val currentItems = _cartItems.value.orEmpty().toMutableList()
        val existingDish = currentItems.find { it.id == dish.id }

        if (existingDish != null) {
            existingDish.quantity += 1
        } else {
            currentItems.add(dish.copy(quantity = 1))
        }

        _cartItems.value = currentItems

        Log.d("CartViewModel", "Updated cart items: ${_cartItems.value}")
    }

    fun removeFromCart(cartItem: DishModel) {
        Log.d("CartViewModel", "Removing from cart: $cartItem")
        val currentCartItems = _cartItems.value.orEmpty().toMutableList()
        currentCartItems.remove(cartItem)
        _cartItems.value = currentCartItems
    }

    fun clearCart() {
        Log.d("CartViewModel", "Clearing cart")
        _cartItems.value = emptyList()
    }

}
package com.example.restauratio.cart

import android.util.Log
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
import com.example.restauratio.databinding.CartItemBinding
import com.example.restauratio.menu.DishModel
import de.hdodenhof.circleimageview.CircleImageView

class CartAdapter(
    private val cartViewModel: CartViewModel
) : RecyclerView.Adapter<CartAdapter.CartViewHolder>() {

    private var cartItems: List<DishModel> = emptyList()

    inner class CartViewHolder(binding: CartItemBinding) : RecyclerView.ViewHolder(binding.root) {
        val dishImage: CircleImageView = binding.imageView2
        val dishName: TextView = binding.textView2
        val dishPrice: TextView = binding.textView
        val quantityTextView: TextView = binding.textView55
        val removeFromCartButton: ImageView = binding.imageView8

        init {
            removeFromCartButton.setOnClickListener {
                val removedDish = cartItems[adapterPosition]
                cartViewModel.removeFromCart(removedDish)
                Toast.makeText(itemView.context, "Danie usunięte z koszyka", Toast.LENGTH_SHORT).show()
            }
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CartViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        val cartItemBinding = CartItemBinding.inflate(inflater, parent, false)
        return CartViewHolder(cartItemBinding)
    }

    override fun onBindViewHolder(holder: CartViewHolder, position: Int) {
        val cartItem = cartItems[position]

        holder.dishName.text = cartItem.name
        holder.dishPrice.text = String.format("%.2f zł", cartItem.price)
        holder.quantityTextView.text = cartItem.quantity.toString()
    }

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

    fun setCartItems(newCartItems: List<DishModel>) {
        Log.d("CartAdapter", "Setting cart items: $cartItems")
        cartItems = newCartItems
        notifyDataSetChanged()
    }
}
package com.example.restauratio.menu

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.OnBackPressedCallback
import androidx.core.view.GravityCompat
import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.restauratio.R
import com.example.restauratio.cart.CartFragment
import com.example.restauratio.cart.CartViewModel
import com.example.restauratio.databinding.FragmentMenuBinding
import com.example.restauratio.loginSession.SessionManager
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject

@AndroidEntryPoint
class MenuFragment : Fragment() {

    @Inject
    lateinit var sessionManager: SessionManager

    private val menuViewModel: MenuViewModel by viewModels()
    private val cartViewModel: CartViewModel by viewModels()

    private var _binding: FragmentMenuBinding? = null
    private val binding get() = _binding!!

    private lateinit var dishAdapter: DishAdapter

    private val actionMenuToAboutUs = R.id.action_menu_to_aboutUs
    private val actionMenuToReservation = R.id.action_menu_to_reservationView
    private val actionMenuToRules = R.id.action_menu_to_rulesView
    private val actionMenuToPrivacyPolicy = R.id.action_menu_to_privacyPolicy
    private val actionLogout = R.id.action_menu_pop
    private val actionMenuToAlerts = R.id.action_menu_to_alerts
    private val actionMenuToProfile = R.id.action_menu_to_profile
    private val actionMenuToOrders = R.id.action_menu_to_orders
    private val actionMenuToCart = R.id.action_menu_to_cartFragment

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentMenuBinding.inflate(inflater, container, false)

        val drawerLayout = binding.drawerLayout
        val mainView: View = binding.root

        mainView.setOnClickListener {
            if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
                drawerLayout.closeDrawer(GravityCompat.START)
            }
        }

        binding.hamburgerButton.setOnClickListener {
            onHamburgerButtonClick()
        }
        binding.imageView6.setOnClickListener{
            findNavController().navigate(actionMenuToAlerts)
        }
        binding.imageView2.setOnClickListener{
            findNavController().navigate(actionMenuToProfile)
        }
        binding.imageView7.setOnClickListener{
            findNavController().navigate(actionMenuToOrders)
        }
        binding.imageView.setOnClickListener {
            findNavController().navigate(actionMenuToCart)
        }

        binding.navigationView.setNavigationItemSelectedListener { menuItem ->
            when (menuItem.itemId) {
                R.id.about_us -> {
                    findNavController().navigate(actionMenuToAboutUs)
                }
                R.id.reservation -> {
                    findNavController().navigate(actionMenuToReservation)
                }
                R.id.rules -> {
                    findNavController().navigate(actionMenuToRules)
                }
                R.id.privacy_policy -> {
                    findNavController().navigate(actionMenuToPrivacyPolicy)
                }
                R.id.logout -> {
                    sessionManager.logout()
                    findNavController().navigate(actionLogout)
                }
            }
            binding.drawerLayout.closeDrawer(GravityCompat.START)
            true
        }

        requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, onBackPressedCallback)

        return binding.root
    }

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

        dishAdapter = DishAdapter(cartViewModel)

        binding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
        binding.recyclerView.adapter = dishAdapter

        menuViewModel.dishes.observe(viewLifecycleOwner) { dishes ->
            dishAdapter.setDishes(dishes)
        }
        menuViewModel.loadDishes(categoryId = null, name = null)

        binding.textInputLayout3.editText?.addTextChangedListener { text ->
            val searchQuery = text.toString().trim()
            menuViewModel.loadDishes(categoryId = null, name = null, searchQuery = searchQuery)
        }
    }

    private fun onHamburgerButtonClick() {
        val drawerLayout = binding.drawerLayout

        if (!drawerLayout.isDrawerOpen(GravityCompat.START)) {
            drawerLayout.openDrawer(GravityCompat.START)
        } else {
            drawerLayout.closeDrawer(GravityCompat.START)
        }
    }

    private val onBackPressedCallback = object : OnBackPressedCallback(true) {
        override fun handleOnBackPressed() {
            if (sessionManager.isLoggedIn()) {
                requireActivity().finish()
            } else {
                findNavController().popBackStack()
            }
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

package com.example.restauratio.menu

import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.restauratio.request.AuthService
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class MenuViewModel @Inject constructor(
    private val authService: AuthService
) : ViewModel() {

    private val _dishes = MutableLiveData<List<DishModel>>()
    val dishes: LiveData<List<DishModel>> get() = _dishes

    fun loadDishes(
        categoryId: Int?,
        name: String?,
        searchQuery: String? = null
    ) {
        viewModelScope.launch {
            try {
                val dishesResponse = authService.getDishes(DishRequest(categoryId, name))
                if (dishesResponse.isSuccessful) {
                    val allDishes = dishesResponse.body()?.dishes ?: emptyList()

                    val filteredDishes = if (!searchQuery.isNullOrBlank()) {
                        allDishes.filter { dish -> dish.name.contains(searchQuery, ignoreCase = true) }
                    } else {
                        allDishes
                    }

                    _dishes.value = filteredDishes
                } else {
                    Log.e("MenuViewModel", "Failed to fetch dishes. Error code: ${dishesResponse.code()}")
                }
            } catch (e: Exception) {
                Log.e("MenuViewModel", "An error occurred while fetching dishes", e)
            }
        }
    }
}
package com.example.restauratio.menu

import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
import com.example.restauratio.cart.CartViewModel
import com.example.restauratio.databinding.MenuItemBinding
import de.hdodenhof.circleimageview.CircleImageView

class DishAdapter(
    private val cartViewModel: CartViewModel
) : RecyclerView.Adapter<DishAdapter.DishViewHolder>() {

    private var dishes: List<DishModel> = emptyList()

    inner class DishViewHolder(binding: MenuItemBinding) : RecyclerView.ViewHolder(binding.root) {
        val dishImage: CircleImageView = binding.imageView2
        val dishName: TextView = binding.textView2
        val dishPrice: TextView = binding.textView
        val addToCartButton: ImageView = binding.imageView8

        init {
            addToCartButton.setOnClickListener {
                val clickedDish = dishes[adapterPosition]
                cartViewModel.addToCart(clickedDish)
                Toast.makeText(itemView.context, "Danie dodane do koszyka", Toast.LENGTH_SHORT).show()
            }
        }

    }


    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DishViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        val menuItemBinding = MenuItemBinding.inflate(inflater, parent, false)
        return DishViewHolder(menuItemBinding)
    }

    override fun onBindViewHolder(holder: DishViewHolder, position: Int) {
        val dish = dishes[position]

        holder.dishName.text = dish.name
        holder.dishPrice.text = String.format("%.2f zł", dish.price)

    }

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

    fun setDishes(newDishes: List<DishModel>) {
        dishes = newDishes
        notifyDataSetChanged()
    }
}
package com.example.restauratio.menu

data class DishModel(
    val id: Int,
    val name: String,
    val description: String,
    val price: Double,
    val dishCategoryIds: List<Int>,
    var quantity: Int = 0
)

data class DishRequest(
    val categoryId: Int?,
    val name: String?
)

data class DishResponse(
    val dishes: List<DishModel>,
    val total: Int
)

不知道为什么会这样

android kotlin mvvm android-livedata dagger-hilt
1个回答
0
投票

当您切换到 CartFragment 时,会创建一个新的fragment 实例,同时也会创建一个新的 viewmodel 实例。为了解决这个问题,引入了共享视图模型的概念,使用

activityViewModels
而不是
viewModels

activityViewModels
与托管片段的活动相关联,而
viewModels
与每个片段相关联。以下是代码外观的示例:

CartFragment

@AndroidEntryPoint
class CartFragment : Fragment() {

    private val cartViewModel: CartViewModel by activityViewModels()
....
}

MenuFragment

@AndroidEntryPoint
class MenuFragment : Fragment() {
...
    private val cartViewModel: CartViewModel by activityViewModels()
...

要了解更多信息,请查看此 Codelab - 跨片段共享视图模型

如果您将数据保存到 db 或 api,则另一种选择是添加一个新函数来获取数据并更新 observable,然后在 CartFragment onviewCreated 上调用该函数。

© www.soinside.com 2019 - 2024. All rights reserved.