Search code examples
androidgoogle-places-apigoogle-placesgoogle-places-autocomplete

GeoDataClient.getAutocompletePredictions - Canceling/Ignoring Previous Requests


Android SDK https://developers.google.com/places/android-sdk/autocomplete (Look for Get place predictions programmatically)

GeoDataClient.getAutocompletePredictions() - I would like to ignore responses that are not the last request... autoComplete typing for example: 'New'->'New Y'->'New Yo'

3 Responses - but I want to catch only the last one.. (Not Using RX)

// Submit the query to the autocomplete API and retrieve a PendingResult that will
   // contain the results when the query completes.
   Task<AutocompletePredictionBufferResponse> results =
           geoDataClient.getAutocompletePredictions(constraint, bounds, typeFilter);
   results.addOnSuccessListener(autocompletePredictions -> {
       if (autoCompletePredictionsListener != null) {
           autoCompletePredictionsListener.onAutoCompleteSuccess(autocompletePredictions);
       }
//****Here I want to ignore(or cancel somewhere before) previous requests
       autocompletePredictions.release();
   });

iOS SDK - Solved By Google Developers https://developers.google.com/places/ios-sdk/reference/interface_g_m_s_autocomplete_fetcher

The delegate will only be called with prediction results if those predictions are for the text supplied in the most recent call to sourceTextHasChanged.


Solution

  • Had a similar need recently and this was what I did to achieve the desired result

    // create a class-scope variable to track the most recent query
    private String lastQuery;
    private GeoDataClient geoDataClient;
    
    // wrap the geoDataClient.getAutocompletePredictions in a class to associate the prediction results with the query that triggered the call
    class AutocompletePredictor {
        String query;
    
        AutocompletePredictor(String query) {
            this.query = query;
        }
    
        Task<AutocompletePredictionBufferResponse> getPredictions(LatLngBounds bounds, AutocompleteFilter typeFilter) {
            return geoDataClient.getAutocompletePredictions(query, bounds, typeFilter);
        }
    }
    
    // modify your method that triggers the autocomplete filter
    void filterAutocomplete(String constraint) {
        // update lastQuery every time this method is called
        lastQuery = constraint;
    
        // Submit the query to the autocomplete API and retrieve a PendingResult that will contain the results when the query completes.
        final AutocompletePredictor predictor = new AutocompletePredictor(constraint);
        Task<AutocompletePredictionBufferResponse> results = predictor.getPredictions(bounds, typeFilter);
    
        results.addOnSuccessListener(autocompletePredictions -> {
            // checks if the query for this filter is same as the most recent query issued to this method
            if (autoCompletePredictionsListener != null && predictor.query.equals(lastQuery)) {
                autoCompletePredictionsListener.onAutoCompleteSuccess(autocompletePredictions);
            }
    
            autocompletePredictions.release();
        });
    }
    

    Edit: Delay calls when user is typing...
    Instead of calling the autocomplete method each time the content of the EditText changes (which can be every time the user types a character), schedule the autocomplete call to wait for a period of time before actually executing. If the EditText content changes again before the waiting period elapses, cancel the previous schedule and re-schedule.

    editText.addTextChangedListener(new TextWatcher() {
        int delayMilliseconds = 500;
        Handler handler = new Handler();
    
        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
    
        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
    
        @Override
        public void afterTextChanged(Editable editable) {
            final String constraint = editable.toString();
    
            // remove all delayed/pending tasks set in the last 500 milliseconds
            handler.removeCallbacksAndMessages(null);
    
            // setup a new delayed task to execute after 500 milliseconds
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    filterAutocomplete(constraint);
                }
            }, delayMilliseconds);
        }
    });