Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
99 views
in Technique[技术] by (71.8m points)

android - Observer serves old data onBackPressed

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...