7

Google has recently updated their Places SDK for android, so now I'm updating my code too. I'm trying to use the AutocompleteSupportFragment to allow the user to set their address.

This is my code:

mAddressEditText = (AutocompleteSupportFragment) getSupportFragmentManager().findFragmentById(R.id.address);
mAddressEditText.setPlaceFields(Arrays.asList(Place.Field.ADDRESS, Place.Field.LAT_LNG));
mAddressEditText.setHint("Address");
mAddressEditText.setText("Test1");                      // Works fine at the beginning, disappears after selecting a place and shows only the hint
mAddressEditText.setOnPlaceSelectedListener(new PlaceSelectionListener() {
    @Override
    public void onPlaceSelected(Place place) {
        Log.d(TAG, "Place Selected");
        // Other Stuff
        mAddressEditText.setText("Test2");              // Doesn't Work, all I can see is the hint
        mAddressEditText.setText(place.getAddress());   // Doesn't Work, all I can see is the hint
    }

    @Override
    public void onError(Status status) {
        Log.e(TAG, "An error occurred: " + status);
        invalidAddressDialog.show();
    }
});

In the previous SDK, the fragment would set the text to the selected address automatically. This doesn't work in the new SDK (not sure if that's intentional or not). So I'm trying to set it manually instead. As you can see in the comments in my code, using setText works fine outside the listeners. Inside the listener they don't.

Am I doing something wrong or is this a bug?

EDIT: So long and I still can't get a proper fix to this. To be perfectly clear, I can get the address correctly from the fragment, the only thing that doesn't work is setText.

However, since some answers state they're not getting the same problem, I started thinking it might be related to the library versions I'm using?

These are the libraries I have in my build.gradle:

api 'com.android.support:appcompat-v7:28.0.0'
api 'com.android.support:support-annotations:28.0.0'

api 'com.android.support:multidex:1.0.3'

api 'com.google.firebase:firebase-core:16.0.8'
api 'com.google.firebase:firebase-auth:16.2.1'
api 'com.google.firebase:firebase-firestore:18.2.0'
api 'com.google.firebase:firebase-storage:16.1.0'
api 'com.google.android.libraries.places:places:1.1.0'
mewais
  • 1,265
  • 3
  • 25
  • 42

10 Answers10

8

setText has been giving me the same problem - it must be a bug I think. However I found a little work around with the hint. In your onPlaceSelected you can put the following:

Java

EditText etPlace = (EditText) autocompleteFragment.getView().findViewById(R.id.places_autocomplete_search_input);
etPlace.setHint(place.getAddress())

Kotlin

val etPlace = autocompleteFragment.view?.findViewById(R.id.places_autocomplete_search_input) as EditText
etPlace.hint = place.address
CacheMeOutside
  • 699
  • 7
  • 24
  • That's how I'm going around it for now, but I can't keep this as a final solution, specially because I can't set the hint color and it looks visually different from all the other components I have. – mewais Apr 30 '19 at 22:00
  • But `setHint()` works just fine inside `onPlaceSelected()`. The problem is `setText()` doesn't. It actually sets the text to the field and sometimes you can see it for a few moments and then the field is clear again. – Victor K. Feb 07 '20 at 08:00
4

This is the code that I am using and it is working perfectly fine.

Make some changes to build.gradle (app level)

Add this to build.gradle:

android{
   ...
   ext {
        googlePlayServicesVersion = "15.0.1"
   }
}

Add those dependencies:

dependencies {
    ...
    //Also if you're using any firebase dependencies make sure that the are up to date
    implementation 'com.google.android.gms:play-services-places:16.0.0'
    implementation 'com.google.android.libraries.places:places:1.1.0'
}
apply plugin: 'com.google.gms.google-services'

In xml layout:

<fragment
                android:id="@+id/autocomplete_fragment"
                android:name="com.google.android.libraries.places.widget.AutocompleteSupportFragment"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

The code in Activity:

private void initGooglePlacesApi() {
        // Initialize Places.
        Places.initialize(getApplicationContext(), "YOUR_API_KEY");
        // Create a new Places client instance.
        PlacesClient placesClient = Places.createClient(getApplicationContext());

        // Initialize the AutocompleteSupportFragment.
        AutocompleteSupportFragment autocompleteFragment = (AutocompleteSupportFragment)
                getSupportFragmentManager().findFragmentById(R.id.autocomplete_fragment);

        autocompleteFragment.setHint(getString(R.string.select_location_search_bar));
//        autocompleteFragment.setLocationRestriction(RectangularBounds.newInstance(
//                new LatLng(34.7006096, 19.2477876),
//                new LatLng(41.7488862, 29.7296986))); //Greece bounds
        autocompleteFragment.setCountry("gr");


        // Specify the types of place data to return.
        autocompleteFragment.setPlaceFields(Arrays.asList(Place.Field.ADDRESS, Place.Field.ADDRESS_COMPONENTS));
        autocompleteFragment.setTypeFilter(TypeFilter.ADDRESS);


        // Set up a PlaceSelectionListener to handle the response.
        autocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
            @Override
            public void onPlaceSelected(Place place) {
                if(place.getAddressComponents().asList().get(0).getTypes().get(0).equalsIgnoreCase("route")){
                    binding.textViewLocation.setText(place.getAddress()); //Works well
                    location = place.getAddress();

                }else{ //If user does not choose a specific place.
                    AndroidUtils.vibratePhone(getApplication(), 200);
                    TastyToast.makeText(getApplicationContext(),
                            getString(R.string.choose_an_address), TastyToast.DEFAULT, TastyToast.CONFUSING);
                }

                Log.i(TAG, "Place: " + place.getAddressComponents().asList().get(0).getTypes().get(0) + ", " + place.getId() + ", " + place.getAddress());
            }

            @Override
            public void onError(Status status) {
                Log.i(TAG, "An error occurred: " + status);
            }
        });
    }
Kwnstantinos Nikoloutsos
  • 1,832
  • 4
  • 18
  • 34
  • That's almost the same as what I did, the only difference being that if statement inside onPlaceSelected and that binding thing inside it (what is that btw?). I tried modifying mine to use that if statement (I don't see how that would help, I did it anyway) and it still doesn't work. – mewais Apr 30 '19 at 21:50
  • I just posted the libraries I'm using in my `build.gradle`, perhaps this might be the cause of the problem? Would you post yours? – mewais Apr 30 '19 at 22:06
  • 1
    I copy and pasted this code from one of my projects. So, this binding object is created using data-binding(check it out if you don't know it). The truth is that I faced some problem with the dependencies at first but now they seem to work pretty fine. I have updated my answer with them. Let me know if that helped you! – Kwnstantinos Nikoloutsos Apr 30 '19 at 22:29
  • But why do you have the `com.google.android.gms:play-services-places:16.0.0`? isn't that for the old API? – mewais May 01 '19 at 21:18
  • I don't really know.. but it is working with these dependencies ! – Kwnstantinos Nikoloutsos May 02 '19 at 15:23
1

I found a pretty simple solution..just delay a little bit the moment you set the text in the EditText. So in your PlaceSelectionListener just do it this way:

Handler().postDelayed({
    mAddressEditText.setText(place.getAddress());
}, 300)

PS: This is kotlin code but It's almost similar in Java

Matthias
  • 999
  • 11
  • 25
  • While this may solve the problem, it is not at all a good solution (pausing the main thread to hopefully affect a UI update, seems hacky). https://stackoverflow.com/a/55611886/1326996 is the correct solution. – barnacle.m Dec 04 '19 at 08:10
  • @barnacle.m Thanks for the comment, I didn't know Handler was blocking the main thread, I am glad that you commented my answer! – Matthias Dec 04 '19 at 15:45
1

By setting "NAME" in setPlaceFields, a selected address is automatically shown in the fragment:

AutocompleteSupportFragment autocompleteFragment = (AutocompleteSupportFragment)
    getSupportFragmentManager().findFragmentById(R.id.autocomplete_fragment);


// Set "Place.Field.NAME" as below here to show the selected item //
autocompleteFragment.setPlaceFields(Arrays.asList(Place.Field.ID, **Place.Field.NAME**,Place.Field.ADDRESS,Place.Field.LAT_LNG));


autocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
    @Override
    public void onPlaceSelected(@NonNull Place place) {
        // TODO: Get info about the selected place. }
 
    @Override
    public void onError(@NonNull Status status) {
        // TODO: Handle the error. }
});
JKD
  • 11
  • 2
0

I believe this is a bug, because it doesn't make sense to have it working like this. What does work is set other autocomplete's texts but not its own. This has to be a bug.

user1556690
  • 1
  • 1
  • 3
0

EDIT: here is my updated answer

# When you are using AutocompleteSupportFragment or AutocompleteActivity
# in Fragments, do this:
public class YourFragment extends Fragment {
/.../
@Override
public void onActivityResult (int requestCode,int resultCode,
 @Nullable Intent data){
 # AUTOCOMPLETE_REQUEST_CODE is just a unique constant, define it
 if (requestCode == AUTOCOMPLETE_REQUEST_CODE) {
   if (resultCode == AutocompleteActivity.RESULT_OK) {
    Place place = Autocomplete.getPlaceFromIntent(data);
    // when resultcode is RESULT_OK
    mAddressEditText.setText(place.getName());
    // Notice this line, update your editText up here
    }else if (resultCode == AutocompleteActivity.RESULT_ERROR) {
    Status status = Autocomplete.getStatusFromIntent(data);
    // Handle error
    } else if (resultCode == AutocompleteActivity.RESULT_CANCELED) {
    // Handle results if canceled
    }
  super.onActivityResult(requestCode, resultCode, data);
 }
}
/.../
}
# If you are extending AppCompatActivity, you might want to do this
# ONLY when you are already doing something in onActivityResult
public class YourActivity extends AppCompatActivity{
/.../
@Override
public void onActivityResult (int requestCode,int resultCode,@Nullable Intent data){
 # your logic here.
 /.../ 
  # if you are already overriding onActivityResult, 
  # do not forget to put this line
  super.onActivityResult(requestCode, resultCode, data);
 }
/.../
}

I was having the problem too. Turns out you HAVE to override this and implement it anyway, whether using AutocompleteSupportFragment or AutocompleteActivity if you are working in Fragments.

If you are using AppCompatActivity you do not have to implement it, but if you are already overiding onActivityResult to do something, do not forget to call the base method super.onActivityResult

dogNoob
  • 1
  • 1
  • 2
  • Sorry I'm getting confused, you mean I'm supposed to override `onActivityResult` even though I'm using place autocomplete fragment not launching a place autocomplete activity?!! – mewais Apr 30 '19 at 21:55
  • if you are extending Fragments instead of AppCompatActivity, you need to override onActivityResult and make sure you put the code above. I was having the same problem with Fragments using navigation components and I was able to set my edittext after I override my onActivityResult. Meanwhile, If you are doing your work in an Activity, which, naturally means you're using AppCompatActivity, you do not need to do anything unless you are already doing something in it. I will update my answer to provide more information – dogNoob May 01 '19 at 07:43
  • have you checked out google place sample? it might help you https://github.com/googlemaps/android-places-demos – dogNoob May 01 '19 at 08:49
0

get the reference of AutoCompleteFragment and then set text to the autocomplete fragment like

autoCompleteFragment.setText("Address")

for reference you can have a look at the documentation

https://developers.google.com/android/reference/com/google/android/gms/location/places/ui/PlaceAutocompleteFragment

Abdul
  • 869
  • 6
  • 14
0

I tried CacheMeOutside's solution but it didn't work at all. So, I decided to try Matthias's solution and it did work because the text actually sets and then immediately removes for some reason. A small delay fixes it. The delay can be as small as 1 millisecond.

If my solution doesn't work for you, you can try to experiment with the delay. It also seems that it doesn't stop view rendering, so you can set any time you want.

private lateinit var autocomplete: AutocompleteSupportFragment

        override fun onPlaceSelected(place: Place) {
            Timer("SetAddress", false).schedule(1) {
                autocomplete.setText(place.address)
            }
        }

The code snippet in Kotlin. If your code is in Java, just find some instrument to delay code execution for some time.

Victor K.
  • 151
  • 4
  • 14
0

The solution by Matthias is working but it is in kotlin. Below is the same implementation in Java

 @Override
 public void onPlaceSelected(Place place) {


                        String name =  place.getName()+", "+place.getAddress();
                      
                        new Handler().postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                autocompleteFragmentDestination.setText(name);
                            }
                        },300);

                    }
Martin Mbae
  • 1,108
  • 1
  • 16
  • 27
0

Simple. Use a Spannable string to set the color!

    val autocompleteFragment = childFragmentManager.findFragmentById(R.id.location_filter_autocomplete) as AutocompleteSupportFragment
    val text = SpannableString("Enter a location")
    text.setSpan(ForegroundColorSpan(Color.BLACK), 0, text.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
    autocompleteFragment.setHint(text)

Do the same inside onPlaceSelectedListener()

Vikram
  • 1
  • 1