dudiktsah
dudiktsah

Reputation: 61

firebase realtime database transaction cause listener callback with data that not committed

I'm using firebase realtime database for android, doing transaction to update an object, what suppose to block 2 users from overriding one each other. that seems to work.

The problem: one user blocked from writing so doTransation() will be called again as should. According to my logic below first doTransation call won't take affect on the server. second doTransation call will do abort. after the first doTransation and before the second, I getting the callback onDataChange() to my ValueEventListener with the data that was rejected/ not committed and before onComplete() called.

any idea why this behavior? how do I change it?

fun onIconClicked(currentGameState: GameState, gameId: String, iconClicked: Long) {
    Log.d(TAG, "onIconClicked() called")

    database.child(GAME_STATE_PATH).child(gameId).runTransaction(object : Transaction.Handler {
        override fun doTransaction(currentData: MutableData): Transaction.Result {

            val gameState = currentData.getValue(GameState::class.java)
                ?: return Transaction.success(currentData)

            // make sure the state from server match the client, and check if won the card        
            return if (gameState == currentGameState && true == currentGameState.users?.get(currentUserId)?.card?.contains(iconClicked) &&
                    true == currentGameState.mainCard?.contains(iconClicked)) {

                // player won card - make the changes in game state...

                currentData.value = gameState
                Log.d(TAG, "doTransaction() winning card, game after = $gameState")

                Transaction.success(currentData)
            } else {
                Log.d(TAG, "doTransaction() aborting")
                Transaction.abort()
            }
        }

        override fun onComplete(error: DatabaseError?, committed: Boolean, currentData: DataSnapshot?) {
            Log.d(TAG, "onIconClicked onComplete() called with: error = $error, committed = $committed, currentData = $currentData")
        }
    })
}

Upvotes: 0

Views: 294

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 599766

I getting the callback onDataChange() to my ValueEventListener with the data that was rejected/ not committed and before onComplete() called.

Listeners on the same client where the transaction runs will indeed see local events for intermediate transaction iterations.

If you don't want these local events to fire, use the overload of runTransaction that takes a second argument called fireLocalEvents, and pass false for that.

So:

database.child(GAME_STATE_PATH).child(gameId).runTransaction(..., false)

Upvotes: 1

Related Questions