Saludos a todos, Estoy desarrollando una aplicación en Android por mi cuenta, aplicando los conocimientos aprendidos en los cursos "Android Basics in Kotlin", "Modern Android app architecture", "Advanced Android in Kotlin" y "Accessibility". La aplicación carga datos de productos y categorías desde Firebase Realtime Database y los muestra en diferentes RecyclerView, dependiendo de la categoría seleccionada.
Mi problema surge al rotar la pantalla, ya que los registros en el RecyclerView se pierden. He intentado implementar LiveData, ViewBinding, MVVM y Repository, pero no logro encontrar la solución. Me gustaría solicitar su ayuda para entender y corregir este problema. Quiero seguir aprendiendo y mejorar mis habilidades en el desarrollo de aplicaciones Android con Kotlin. Agradezco cualquier sugerencia o consejo que puedan ofrecerme. Muchas gracias de antemano. -- You received this message because you are subscribed to the Google Groups "Android Developers" group. To unsubscribe from this group and stop receiving emails from it, send an email to android-developers+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/android-developers/4abc479e-168c-4169-8c89-dff59e0edcb5n%40googlegroups.com.
class ProductListViewModel : ViewModel() { private val productRepository = ProductRepository() // Products private val productList: LiveData<List<Product>> = productRepository.getProductList() // Types private val productTypeList: LiveData<List<ProductType>> = productRepository.getProductTypeList() fun getProductList(): LiveData<List<Product>> { return productList } fun getProductTypeList(): LiveData<List<ProductType>> { return productTypeList } fun getProductsByCategory(category: String): LiveData<List<Product>> { return productRepository.getProductsByCategory(category) } }
class ProductListFragment : Fragment(), ProductItemClickListener, ProductTypeItemClickListener { enum class SortOrder { ASC, DESC } private var _binding: FragmentProductListBinding? = null private val binding get() = _binding!! // Product Types private lateinit var rvProductTypes: RecyclerView private lateinit var productTypeAdapter: ProductCategoryAdapter // Products private lateinit var rvProducts: RecyclerView private lateinit var productAdapter: ProductAdapter // ViewModel private val productListViewModel: ProductListViewModel by viewModels() override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { _binding = FragmentProductListBinding.inflate(inflater, container, false) return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // Product Type rvProductTypes = binding.rvProductCategory rvProductTypes.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false) productTypeAdapter = ProductCategoryAdapter() rvProductTypes.adapter = productTypeAdapter // Asignar el listener al adapter productTypeAdapter.setItemClickListener(this) productListViewModel.getProductTypeList().observe(viewLifecycleOwner) { productTypeList -> productTypeAdapter.productTypeList = productTypeList productTypeAdapter.notifyDataSetChanged() } // Products rvProducts = binding.rvProducts rvProducts.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false) productAdapter = ProductAdapter() rvProducts.adapter = productAdapter // Asignar el listener al adapter productAdapter.setItemClickListener(this) productListViewModel.getProductList().observe(viewLifecycleOwner) { productList -> productAdapter.productList = productList productAdapter.notifyDataSetChanged() } // Filter binding?.ivFilterProducts?.setOnClickListener { view -> // Código del evento onClick del botón val popup = PopupMenu(requireContext(), view) popup.inflate(R.menu.menu_product_sort) popup.setOnMenuItemClickListener { item -> when (item.itemId) { R.id.sort_asc -> { sortProducts(SortOrder.ASC) true } R.id.sort_desc -> { sortProducts(SortOrder.DESC) true } else -> false } } popup.show() } } /** * Sorts the product list by name in the specified order and updates the adapter. * @param sortOrder The order in which to sort the products. */ private fun sortProducts(sortOrder: SortOrder) { val sortedProductList = when (sortOrder) { SortOrder.ASC -> productListViewModel.getProductList().value?.sortByNameAsc() SortOrder.DESC -> productListViewModel.getProductList().value?.sortByNameDesc() } sortedProductList?.let { productAdapter.productList = it productAdapter.notifyDataSetChanged() } } override fun onDestroyView() { super.onDestroyView() _binding = null } // Declara el TAG en la parte superior de tu clase private val TAG = "onProductTypeItemClick" private var beforePosition = RecyclerView.NO_POSITION private var afterPosition = RecyclerView.NO_POSITION /** * Este método se llama cuando se hace clic en un ProductType en el RecyclerView. * Muestra un Toast con el nombre y la edad del usuario. */ override fun onProductTypeItemClick(productType: ProductType) { // Crear el mensaje a mostrar en el Toast val message = "Nombre: ${productType.name}" // Mostrar un Toast con el mensaje Toast.makeText(context, message, Toast.LENGTH_SHORT).show() // Obtener la posición del registro seleccionado val position = productTypeAdapter.productTypeList.indexOf(productType) // Mostrar la posición en el Logcat Log.d(TAG, "XXXXXbeforePosition: $beforePosition") Log.d(TAG, "XXXXXPosition: $position") // Pintar el background de la posición seleccionada // 1. Obtener la vista de la tarjeta seleccionada val selectedViewHolder = rvProductTypes.findViewHolderForAdapterPosition(position) // 2. Obtener la vista de la tarjeta a modificar val selectedView = selectedViewHolder?.itemView?.findViewById<ConstraintLayout>(R.id.cl_product_background) // 3. Obtener la vista de la tarjeta anteriormente seleccionada val beforeViewHolder = rvProductTypes.findViewHolderForAdapterPosition(beforePosition) val beforeView = beforeViewHolder?.itemView?.findViewById<ConstraintLayout>(R.id.cl_product_background) // Cambiar el fondo de la tarjeta seleccionada selectedView?.setBackgroundResource(R.drawable.selected_item_background) // Reestablecer el fondo de la tarjeta anteriormente seleccionada beforeView?.setBackgroundResource(R.drawable.default_item_background) // Actualizar el valor de la posición anterior beforePosition = position } override fun onProductTypeIdItemClick(productTypeId: String) { Log.e("onProductTypeItemClick", "START onProductTypeIdItemClick_____________________________________________________________") Log.e("onProductTypeItemClick", "roductTypeId: $productTypeId") Toast.makeText(context, "productTypeId: $productTypeId", Toast.LENGTH_SHORT).show() rvProducts.adapter = productAdapter // deberías actualizar el adaptador de productos en lugar del de tipos de producto productListViewModel.getProductsByCategory(productTypeId).observe(viewLifecycleOwner, { productList -> productAdapter.productList = productList productAdapter.notifyDataSetChanged() }) Log.e(TAG, "rvProductTypes: ${rvProductTypes}") Log.e(TAG, "size: ${rvProductTypes.size}") Log.e("onProductTypeItemClick", "END onProductTypeIdItemClick_____________________________________________________________") } /** * Product * */ override fun onProductItemClick(product: Product) { // Crear el mensaje a mostrar en el Toast val message = "Nombre: ${product.name}" // Mostrar un Toast con el mensaje Toast.makeText(context, message, Toast.LENGTH_SHORT).show() Log.e("onProductItemClick", "product ${product} ") // id=null, name=Producto xxx1, description=Descripción del Producto 1, price=10.0, available=true, type=0001 } override fun onProductIdItemClick(productId: String) { Log.e("onProductIdItemClick", "productId: $productId") Toast.makeText(context, "Producto Id: $productId", Toast.LENGTH_SHORT).show() } }