Firebase addOnSuccessListener() and addOnFailureListener() to a .setValue() call in Kotlin

My app will allow users to make purchases, and once I get the user’s payment, I want to ensure that the proper record is created in my firebase database. When the record write succeeds, I want to show them a “purchase complete” fragment, and if the record is not created, I want to at least warn them with an error code.

Some groundwork:

First, an error message display mechanism is needed. I have been pretty happy with a toast-style message that is conveyed to my View Model and observed in my fragments. To do this, I use a MutableLiveData String in my View Model:

// Excerpt from viewModel.kt:
// Store any error Message Generated:
var errorToastMe = MutableLiveData("")

Now, observe the MutableLiveData in the fragments onCreateView:

//Excerpt from FragmentCheckout.kt
// show Error Messages:
viewModel.errorToastMe.observe(viewLifecycleOwner) { errorMessage ->
    if (! errorMessage.isNullOrEmpty() ){
        Toast.makeText(context,errorMessage, Toast.LENGTH_LONG).show()
        // once the error is displayed set it to null
        viewModel.resetErrorMessage()
    }
}

View Model call to the Repository to Create the Record:

//Excerpt from viewModel.kt
fun createSubscriptionRecord(
    offer: SubscriptionOffer,
    successHandler: () -> Unit,
    failureHandler: () -> Unit,
    ){

    repository.createRecord(offer, successHandler, failureHandler)
}

You might note the second and third parameters are functions, and those are passed to the repository’s “createRecord” method.

OnClickTakeMyMoney()

Now we are getting to the meat and potatoes, collecting the payment, and then creating the record in Firebase. Here is my click handler function in my fragment:

// Excerpt from FragmentCheckout.kt
fun onClickTakeMyMoney(chosenOffer: Offer?){

    chosenOffer?.let { offer ->
        val paymentSuccess = viewModel.authorizePayment(offer.price.toFloat())

        if (paymentSuccess){

            viewModel.createRecord(offer ,
                successHandler = {
                    // show payment approved
                    val action = NavGraphDirections.actionPaymentApproved()
                    view?.findNavController()?.navigate(action)
                                 },
                failureHandler = {
                    viewModel.errorToastMe.value = "Error 1001 : Payment Taken, Payment Record Not Created!"
                })

        } else {
            // show payment declined fragment.
        }

When calling viewModel.createRecord, the first parameter is an offer object complete with price, description, image URL to represent the purchase, and notes that will be added to the firebase database. The second and third parameters are functions that specify what the addOnSuccessListener() and addOnFailureListener() should do. The view model just passes all of those options onto purchaseRepository.createRecord.

Inside of purchaseRepository.createRecord is the actual Firebase .setValue code, which calls those passed methods:

// Excerpt from purchasesRepository.kt
fun createSubscriptionRecord(
        offer: Offer,
        successHandler: () -> Unit,
        failureHandler: () -> Unit){

 subscriptionViewModel.authenticatedUser.firebaseDbKey.value?.let{ fireKey ->
            database.child("subscriptions")
                .child(fireKey)
                .child(level3key)
                .setValue(Record)
                .addOnSuccessListener() {
                    successHandler()
                }.addOnFailureListener {
                    failureHandler()
                }

Leave a Reply

Your email address will not be published. Required fields are marked *