0

I have created a Place[] type array p to store the place obtained through fetchPlace() method. I have just shown the some lines code of a function which I have to call. But when I call this function the 1st logd line is executed first which shows value of p[0] as null. As fetching a place takes some time, so I delayed 2nd logd line. Here, p[0] is not null. Please have a look at the code below:

final Place[] p = new Place[1];

final String placeId = place.get("place_id");

        final List<Place.Field> placeFields = Arrays.asList(
                Place.Field.PHONE_NUMBER,
                Place.Field.LAT_LNG
        );

        final FetchPlaceRequest request = FetchPlaceRequest.newInstance(placeId, placeFields);

        placesClient.fetchPlace(request).addOnSuccessListener((response) -> {

            p[0] = response.getPlace();
            
        }).addOnFailureListener((exception) -> {
            Log.i(TAG, "Place not found: " + exception.getMessage());
        });

        Log.d(TAG, "Place: " + p[0]);
        
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG, "Place Delayed: " + p[0]);
            }
        }, 1000);

Here is the two logd outputs: 1st : D/MapsFragment: Place: null 2nd : D/MapsFragment: Place Delayed: Place{address=null, addressComponents=null, businessStatus=null, attributions=[], id=null, latLng=lat/lng: (19.0255944,73.0935353), name=null, openingHours=null, phoneNumber=+91 1800 208 1234, photoMetadatas=null, plusCode=null, priceLevel=null, rating=null, types=null, userRatingsTotal=null, utcOffsetMinutes=null, viewport=null, websiteUri=null}

I want to ask why does the code inside addOnSuccessListener doesn't run before logd which is below it ? Thanks in advance !

Aditya
  • 3
  • 2
  • 3
    It's because it's a *listener* - the code passed to `addOnSuccessListener` is specifically set aside to be run only once success occurs. You add the listener, and immediately print the value of `p` before the listener is called. – nanofarad Jul 21 '21 at 17:50
  • @nanofarad My purpose is to set a `TextView` with the phone number which I can obtain from place `p[0]`. One way is I can write the code of `setText()` inside _listener_. But what can I do if I want to achieve this outside of _listener_ ? – Aditya Jul 21 '21 at 17:59
  • 1
    I don't know of a clean way to do this outside of the listener. The point of the listener is that it'll fire when the result is ready, and you can use it to set the text at that time. With that said, my Android knowledge isn't very in depth, so I'll defer to others who might have better suggestions. – nanofarad Jul 21 '21 at 18:01
  • @nanofarad Thanks for replying. Your comment was useful to me. – Aditya Jul 21 '21 at 18:19

2 Answers2

1

The comment of nanofarad actually sums it up pretty nicely.

[...] the code passed to addOnSuccessListener is specifically set aside to be run only once success occurs. You add the listener, and immediately print the value of p before the listener is called

Your OnSuccessListener is only getting executed if the lookup of the place was actually successful. Your code however continues to execute and results in p[0] to be null.

I am not familiar with the Google Places API nor Android Development, but judging from the docs / 2, you shouldn't need the listener if you don't make use of it.

Just submit your Task normally and wait until an result is available.

Task<FetchPlaceResponse> fetchPlaceRequest = placesClient.fetchPlace(request);

while (true) {
  Thread.sleep(100);
  try {
    TResult result = fetchPlaceRequest.getResult();
    p[0] = result.getPlace();
    break;
  } catch (IllegalStateException ise) {} catch (InterruptedException ie) {
    break;
  }
}

The sleep function is added to avoid high CPU use. However, this is my generic Java approach since I am not familiar with the API / environment.

maio290
  • 6,440
  • 1
  • 21
  • 38
  • 1
    As a tip - comments are pretty ephemeral, and can disappear during cleanup, mod actions, etc. Feel free to paraphrase or quote directly from my comment if you think it might be useful to future readers (as the comment itself is more likely to disappear) – nanofarad Jul 21 '21 at 18:20
  • @maio290 I'll apply this approach too. Thanks for the reply. – Aditya Jul 21 '21 at 18:20
0

You are assigning the p[0] in addOnSuccessListener which is a callback which will be executed not instantly but after when the response is received. So, the value to p[0] is never assigned before the Log statement.

Refer to this stack overflow answer for more info regarding callbacks.

Nikhil Jain
  • 649
  • 5
  • 11