Im a bit lost at this, searched high and low.
This is an Kotlin Android + Firebase ecommerce app.
In the product detail view fragment I have a button which I enable/disable depending if the product is already in cart. This works fine but when I add product to cart and go to cart and press back, button is enabled even though product is in the cart. This is some wrong doing of mine as I can see in the logcat that user cart is not updated and fragments sees it as empty even though my firestore gets data correctly immediately and button gets disabled when I enter product detail view from recycler view again(not via back press). So it seems going straight to the fragment gets correct data but recreating it from backstack has some cache involved? It works differently, idk. Scope of this might be bigger, it would be amazing if someone could point me in the right direction. Maybe snapshotListener would be a way?
Product Detail Fragment
class ProductDetailFragment : RootFragment(), View.OnClickListener {
private lateinit var viewModel: ProductDetailViewModel
private lateinit var viewModelFactory: ProductDetailViewModelFactory
private lateinit var binding: FragmentDetailProductBinding
private lateinit var repository: FirebaseCloud
private lateinit var auth: FirebaseAuth
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = DataBindingUtil.inflate(
inflater,
R.layout.fragment_detail_product,
container,
false
)
auth = Firebase.auth
repository = FirebaseCloud()
binding.buttonAddToCart.setOnClickListener(this)
viewModelFactory = ProductDetailViewModelFactory(
ProductDetailFragmentArgs
.fromBundle(requireArguments())
.productUid
)
viewModel = ViewModelProvider(this, viewModelFactory)
.get(ProductDetailViewModel::class.java)
viewModel.product.observe(viewLifecycleOwner, {
binding.textProductNameDetail.text = it?.name
binding.textProductDescriptionDetail.text = it?.description
binding.textProductPriceDetail.text = priceFormat(it.price)
val image = binding.imageProductImageDetaills
Glide.with(requireView())
.load(it.imageUrl)
.into(image)
})
viewModel.user?.observe(viewLifecycleOwner, {
val state = checkForProductInCart(it)
setButtonState(state)
Log.d("observer", "${it.cart}")
})
return binding.root
}
private fun priceFormat(price: Long?): String {
val input = DecimalFormat("£###,###0.00")
return input.format(price)
}
// Check if viewed product is already in cart
private fun checkForProductInCart(currentUser: User): Boolean {
val cart = currentUser.cart
val productUid = ProductDetailFragmentArgs.fromBundle(requireArguments()).productUid
return if (cart != null) productUid !in cart
else true
}
// Enable or Disable add to cart button
private fun setButtonState(state: Boolean) {
val button = binding.buttonAddToCart
button.isEnabled = state
if (state) button.text = getString(R.string.add_to_cart_button)
else button.text = getString(R.string.button_in_cart_text)
}
// Handle clicks in the fragment
override fun onClick(view: View?) {
when (view) {
binding.buttonAddToCart ->
if (auth.currentUser == null) {
navigateToLogin()
} else {
repository.addToCart(
ProductDetailFragmentArgs
.fromBundle(requireArguments())
.productUid
)
setButtonState(false)
}
}
}
}
ViewModel
class ProductDetailViewModel(productUid: String) : ViewModel() {
private val repository = FirebaseCloud()
val product = repository.getSingleProduct(productUid)
val user = repository.getUserData()
}
Repo
class FirebaseCloud {
private val auth = FirebaseAuth.getInstance()
private val cloud = FirebaseFirestore.getInstance()
private val _currentUser = MutableLiveData<User>()
val currentUser: LiveData<User>
get() = _currentUser
fun getUserData(): LiveData<User>? {
val cloudResult = MutableLiveData<User>()
if (auth.currentUser != null) {
val uid = auth.currentUser?.uid
cloud.collection("users")
.document(uid!!)
.get()
.addOnSuccessListener {
if (auth.currentUser != null) {
val user = it.toObject(User::class.java)
cloudResult.postValue(user)
}
}
.addOnFailureListener {
Log.d("repo", it.message.toString())
}
return cloudResult
}
return null
}
fun createNewUser(user: User) {
cloud.collection("users")
.document(user.uid!!)
.set(user)
.addOnSuccessListener {
val newUser = User(
uid = user.uid,
firstName = user.firstName,
lastName = user.lastName,
email = user.email,
listOf()
)
_currentUser.value = newUser
}
}
fun getProducts(): LiveData<List<Product>> {
val cloudResult = MutableLiveData<List<Product>>()
cloud.collection("products")
.get()
.addOnSuccessListener {
val product = it.toObjects(Product::class.java)
cloudResult.postValue(product)
}
.addOnFailureListener {
Log.d("getProducts", it.message.toString())
}
return cloudResult
}
fun getSingleProduct(uid: String): LiveData<Product> {
val cloudResult = MutableLiveData<Product>()
cloud.collection("products")
.document(uid)
.get()
.addOnSuccessListener {
val product = it.toObject(Product::class.java)
cloudResult.postValue(product)
}
.addOnFailureListener {
Log.d("getSingleProduct", it.message.toString())
}
return cloudResult
}
fun addToCart(productUid: String) {
if (auth.currentUser != null) {
cloud.collection("users")
.document(auth.currentUser?.uid!!)
.update("cart", FieldValue.arrayUnion(productUid))
.addOnSuccessListener {
Log.d("cart", "Added to Cart")
}
.addOnFailureListener {
Log.d("cart", it.message.toString())
}
}
}
fun removeFromCart(product: Product) {
cloud.collection("users")
.document(auth.currentUser?.uid!!)
.update("cart", FieldValue.arrayRemove(product.uid))
.addOnSuccessListener {
Log.d("cart", "Removed from Cart")
}
.addOnFailureListener {
Log.d("cart", it.message.toString())
}
}
fun getProductsFromCart(list: List<String>?): LiveData<List<Product>> {
val cloudResult = MutableLiveData<List<Product>>()
if (!list.isNullOrEmpty()) {
cloud.collection("products")
.whereIn("uid", list)
.get()
.addOnSuccessListener {
val cartList = it.toObjects(Product::class.java)
cloudResult.postValue(cartList)
}
.addOnFailureListener {
Log.d("getCart", it.message.toString())
}
}
return cloudResult
}
}
question from:
https://stackoverflow.com/questions/65876278/observer-serves-old-data-onbackpressed 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…