0

I am cross-platforming my app using Android and iOS and Firebase. In the iOS app, I have a option for the driver to use bids for the requested ride, whereas in the android app, it is just a calculated price.

If the Android rider requests a ride with an iOS driver, the iOS driver can offer a discounted bid rather than the calculated ridePrice.

In Firebase, in the RideRequests node, it adds ridePrice as the price to be paid but if its a bid price, it also adds a bidPrice. I am trying to set it up that if 'rideBidPrice' exists, then rideAmt = rideBidPrice but if not, then rideAmt = ridePrice.

Unfortunately, what I am doing isn't getting to the PayPalPayment method.

How can I do this?

firebase db:

"RideRequests" : {
    "buIpWNEFgmZJWN3jIB9IwS8r74d2" : { // rider Id
      "archiveTimestamp" : "2019-03-17 22:00",
      "currentAddress" : "2 Peel Plaza",
      "destAddress" : "Courtenay Bay Causeway",
      "destLat" : 47.277879500000004,
      "destLong" : -63.04432369999999,
      "driver" : "Dean Winchester",
      "driverID" : "nD1v8oxHv3ObdQAKeKjuTt6f5TL2",
      "rideBidPrice" : 5.74,
      "ridePrice" : 8.38,
      "riderPaid" : "false",
      "status" : "driverBid",
      "userId" : "buIpWNEFgmZJWN3jIB9IwS8r74d2",
      "username" : "riderANDROID"
    }

Code:

private void checkForBids() {

    Log.e(TAG, "checkForBids");

    DatabaseReference bids = FirebaseDatabase.getInstance().getReference(Common.request_tbl)
            .child(riderId).child("rideBidPrice");
    bids.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            bidPrice = dataSnapshot.getValue(Double.class);
            if (bidPrice != null) {
                rideAmt = bidPrice;
            } else {
                rideAmt = ridePrice;
            }
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });
}


private void payPalPayment() {

    Log.e(TAG, "payPalPayment");

    PayPalPayment payment = new PayPalPayment(new BigDecimal(rideAmt),
                "CAD", "Ryyde Payment ", PayPalPayment.PAYMENT_INTENT_SALE);

    // PaymentActivity is created by PayPal API
    Intent intent = new Intent(this, PaymentActivity.class);

    intent.putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, config);
    intent.putExtra(PaymentActivity.EXTRA_PAYMENT, payment);

    startActivityForResult(intent, PAYPAL_REQUEST_CODE);
}

I also tried putting the payPalPayment method inside the block but won't work because of the intent.

EDIT #1

This works:

As per @AlexMamo post to below post:

How to return DataSnapshot value as a result of a method?

I have added an interface:

 public interface MyCallback {
    void onCallback(Double value); 
}

The method that is actually getting the data from the database:

public void readData(final MyCallback myCallback) {

    Log.e(TAG, "readData");

    DatabaseReference bids = FirebaseDatabase.getInstance().getReference(Common.request_tbl)
            .child(riderId).child("rideBidPrice");
    bids.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            Double value = dataSnapshot.getValue(Double.class);
            myCallback.onCallback(value);

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });
}

Then I call the method inside the PayPalPayment method like this:

 private void payPalPayment() {

    readData(new MyCallback() {
        @Override
        public void onCallback(Double value) {
            PayPalPayment payment = new PayPalPayment(new BigDecimal(value),
                    "CAD", "Ryyde Payment ", PayPalPayment.PAYMENT_INTENT_SALE);

            // PaymentActivity is created by PayPal API
            Intent intent = new Intent(RiderHome.this, PaymentActivity.class);

            intent.putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, config);
            intent.putExtra(PaymentActivity.EXTRA_PAYMENT, payment);

            startActivityForResult(intent, PAYPAL_REQUEST_CODE);
        }
    });
}
halfer
  • 19,824
  • 17
  • 99
  • 186
LizG
  • 2,246
  • 1
  • 23
  • 38
  • It may be easier to create the logic that selects your rideAmt separate from the listener, so in the listener you just set either rideBidPrice or ridePrice and have a separate method "BigDecimal getRideAmount(Object object) {}" that returns your correct ride amount based on the rules you propose. This method can return the BigDecimal and be used directly in the paypal payment method. – Ajibola Mar 18 '19 at 01:57
  • Can we not set it into a constant variable? – LizG Mar 18 '19 at 02:35
  • It's like a variable on a different thread, I think it requires those const or static way to access it. Or put `addListenerForSingleValueEvent ` inside your `payPalPayment(){...}`? – Wesely Mar 18 '19 at 03:27
  • I tried that. Wouldnt work cause of the intent – LizG Mar 18 '19 at 04:25
  • I see now. You do the same mistake. Trying to log `Log.e(TAG, "readData: value: " + value);` outside the callback, won't work. What you have to do, you need to move all your logic inside `onCallback()` method. This is asynchronous programming. If you move the log statement inside the method, do you have the expected behaviour? – Alex Mamo Mar 18 '19 at 19:44

1 Answers1

1

You cannot create your rideAmt as a global variable and simply use it inside your payPalPayment() method because the Firebase API is asynchronous, meaning that onDataChange() method returns immediately after it's invoked, and the callback from the Task it returns, will be called some time later. There are no guarantees about how long it will take. So it may take from a few hundred milliseconds to a few seconds before that data is available. Because that method returns immediately, the value of your rideAmt variable you're trying to use it outside the onDataChange() method, will not have been populated from the callback yet.

Basically, you're trying to use the value of rideAmt synchronously from an API that's asynchronous. That's not a good idea. You should handle the API asynchronously as intended.

A quick solve for this problem would be to move all the logic that exist in your payPalPayment() method right inside the onDataChange() method. In this way, the data that you are trying to get will be available at that time.

If you need to use it outside the callback, I recommend you see the last part of my anwser from this post in which I have explained how it can be done using a custom callback. You can also take a look at this video for a better understanding.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • I tried to do it like the video, but it is still coming up null. I also tried to place the listener inside the PayPalPayment method and the PayPalMethod inside the listener, both would not work because of the intent for the PayPal vc. – LizG Mar 18 '19 at 18:47
  • 1
    @LizG Please edit your question with what you have tried. – Alex Mamo Mar 18 '19 at 18:54