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 [email protected].
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()
}
}