Saltar al contenido

Cómo implementar el autocompletado de Google Places mediante programación

Después de de esta prolongada recopilación de información dimos con la respuesta este disgusto que presentan ciertos los lectores. Te brindamos la respuesta y esperamos serte de gran ayuda.

Solución:

Nueva versión 2019

build.gradle (Módulo: aplicación)

implementation 'com.google.android.gms:play-services-maps:17.0.0'
implementation 'com.google.android.gms:play-services-location:17.0.0'
implementation 'com.google.android.gms:play-services-places:17.0.0'
implementation 'com.google.android.libraries.places:places:1.1.0'

Diseño de actividad



    

    
    

Actividad

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import com.google.android.libraries.places.api.Places;
import com.google.android.libraries.places.api.model.Place;
import com.zaaibo.drive.R;
import com.zaaibo.drive.adapter.PlacesAutoCompleteAdapter;

public class MapsActivity extends AppCompatActivity implements PlacesAutoCompleteAdapter.ClickListener

    private PlacesAutoCompleteAdapter mAutoCompleteAdapter;
    private RecyclerView recyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_settings);

        Places.initialize(this, getResources().getString(R.string.google_maps_key));

        recyclerView = (RecyclerView) findViewById(R.id.places_recycler_view);
        ((EditText) findViewById(R.id.place_search)).addTextChangedListener(filterTextWatcher);

        mAutoCompleteAdapter = new PlacesAutoCompleteAdapter(this);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        mAutoCompleteAdapter.setClickListener(this);
        recyclerView.setAdapter(mAutoCompleteAdapter);
        mAutoCompleteAdapter.notifyDataSetChanged();
    

    private TextWatcher filterTextWatcher = new TextWatcher() 
        public void afterTextChanged(Editable s) 
            if (!s.toString().equals("")) 
                mAutoCompleteAdapter.getFilter().filter(s.toString());
                if (recyclerView.getVisibility() == View.GONE) recyclerView.setVisibility(View.VISIBLE);
             else 
                if (recyclerView.getVisibility() == View.VISIBLE) recyclerView.setVisibility(View.GONE);
            
        
        public void beforeTextChanged(CharSequence s, int start, int count, int after)  
        public void onTextChanged(CharSequence s, int start, int before, int count)  
    ;

    @Override
    public void click(Place place) 
        Toast.makeText(this, place.getAddress()+", "+place.getLatLng().latitude+place.getLatLng().longitude, Toast.LENGTH_SHORT).show();
    

Adaptador

import android.content.Context;
import android.graphics.Typeface;
import android.text.style.CharacterStyle;
import android.text.style.StyleSpan;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.Tasks;
import com.google.android.libraries.places.api.model.AutocompletePrediction;
import com.google.android.libraries.places.api.model.AutocompleteSessionToken;
import com.google.android.libraries.places.api.model.Place;
import com.google.android.libraries.places.api.net.FetchPlaceRequest;
import com.google.android.libraries.places.api.net.FetchPlaceResponse;
import com.google.android.libraries.places.api.net.FindAutocompletePredictionsRequest;
import com.google.android.libraries.places.api.net.FindAutocompletePredictionsResponse;
import com.google.android.libraries.places.api.net.PlacesClient;
import com.zaaibo.drive.R;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class PlacesAutoCompleteAdapter extends RecyclerView.Adapter implements Filterable 
    private static final String TAG = "PlacesAutoAdapter";
    private ArrayList mResultList = new ArrayList<>();

    private Context mContext;
    private CharacterStyle STYLE_BOLD;
    private CharacterStyle STYLE_NORMAL;
    private final PlacesClient placesClient;
    private ClickListener clickListener;

    public PlacesAutoCompleteAdapter(Context context) 
        mContext = context;
        STYLE_BOLD = new StyleSpan(Typeface.BOLD);
        STYLE_NORMAL = new StyleSpan(Typeface.NORMAL);
        placesClient = com.google.android.libraries.places.api.Places.createClient(context);
    

    public void setClickListener(ClickListener clickListener) 
        this.clickListener = clickListener;
    

    public interface ClickListener 
        void click(Place place);
    

    /**
     * Returns the filter for the current set of autocomplete results.
     */
    @Override
    public Filter getFilter() 
        return new Filter() 
            @Override
            protected FilterResults performFiltering(CharSequence constraint) 
                FilterResults results = new FilterResults();
                // Skip the autocomplete query if no constraints are given.
                if (constraint != null) 
                    // Query the autocomplete API for the (constraint) search string.
                    mResultList = getPredictions(constraint);
                    if (mResultList != null) 
                        // The API successfully returned results.
                        results.values = mResultList;
                        results.count = mResultList.size();
                    
                
                return results;
            

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) 
                if (results != null && results.count > 0) 
                    // The API returned at least one result, update the data.
                    notifyDataSetChanged();
                 else 
                    // The API did not return any results, invalidate the data set.
                    //notifyDataSetInvalidated();
                
            
        ;
    


    private ArrayList getPredictions(CharSequence constraint)  TimeoutException e) 
            e.printStackTrace();
        

        if (autocompletePredictions.isSuccessful()) 
            FindAutocompletePredictionsResponse findAutocompletePredictionsResponse = autocompletePredictions.getResult();
            if (findAutocompletePredictionsResponse != null)
                for (AutocompletePrediction prediction : findAutocompletePredictionsResponse.getAutocompletePredictions()) 
                    Log.i(TAG, prediction.getPlaceId());
                    resultList.add(new PlaceAutocomplete(prediction.getPlaceId(), prediction.getPrimaryText(STYLE_NORMAL).toString(), prediction.getFullText(STYLE_BOLD).toString()));
                

            return resultList;
         else 
            return resultList;
        

    

    @NonNull
    @Override
    public PredictionHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) 
        LayoutInflater layoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View convertView = layoutInflater.inflate(R.layout.place_recycler_item_layout, viewGroup, false);
        return new PredictionHolder(convertView);
    

    @Override
    public void onBindViewHolder(@NonNull PredictionHolder mPredictionHolder, final int i) 
        mPredictionHolder.address.setText(mResultList.get(i).address);
        mPredictionHolder.area.setText(mResultList.get(i).area);
    

    @Override
    public int getItemCount() 
        return mResultList.size();
    

    public PlaceAutocomplete getItem(int position) 
        return mResultList.get(position);
    

    public class PredictionHolder extends RecyclerView.ViewHolder implements View.OnClickListener 
        private TextView address, area;
        private LinearLayout mRow;

        PredictionHolder(View itemView) 
            super(itemView);
            area = itemView.findViewById(R.id.place_area);
            address = itemView.findViewById(R.id.place_address);
            mRow = itemView.findViewById(R.id.place_item_view);
            itemView.setOnClickListener(this);
        

        @Override
        public void onClick(View v) 
            PlaceAutocomplete item = mResultList.get(getAdapterPosition());
            if (v.getId() == R.id.place_item_view) 

                String placeId = String.valueOf(item.placeId);

                List placeFields = Arrays.asList(Place.Field.ID, Place.Field.NAME, Place.Field.LAT_LNG, Place.Field.ADDRESS);
                FetchPlaceRequest request = FetchPlaceRequest.builder(placeId, placeFields).build();
                placesClient.fetchPlace(request).addOnSuccessListener(new OnSuccessListener() 
                    @Override
                    public void onSuccess(FetchPlaceResponse response) 
                        Place place = response.getPlace();
                        clickListener.click(place);
                    
                ).addOnFailureListener(new OnFailureListener() 
                    @Override
                    public void onFailure(@NonNull Exception exception) 
                        if (exception instanceof ApiException) 
                            Toast.makeText(mContext, exception.getMessage() + "", Toast.LENGTH_SHORT).show();
                        
                    
                );
            
        
    

    /**
     * Holder for Places Geo Data Autocomplete API results.
     */
    public class PlaceAutocomplete 

        public CharSequence placeId;
        public CharSequence address, area;

        PlaceAutocomplete(CharSequence placeId, CharSequence area, CharSequence address) 
            this.placeId = placeId;
            this.area = area;
            this.address = address;
        

        @Override
        public String toString() 
            return area.toString();
        
    

public class PlaceArrayAdapter extends ArrayAdapter implements Filterable 

    private static final String TAG = "PlaceArrayAdapter";
    private final PlacesClient placesClient;
    private RectangularBounds mBounds;
    private ArrayList mResultList = new ArrayList<>();
    public Context context;

    /**
     * Constructor
     *
     * @param context  Context
     * @param resource Layout resource
     * @param bounds   Used to specify the search bounds
     * @param filter   Used to specify place types
     */
    public PlaceArrayAdapter(Context context, int resource, RectangularBounds bounds) 
        super(context, resource);
        this.context = context;
        mBounds = bounds;
        placesClient = com.google.android.libraries.places.api.Places.createClient(context);
    


    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) 
        View view = super.getView(position, convertView, parent);
        TypefaceHelper.typeface(view);
        return view;
    

    @Override
    public int getCount() 
        if (mResultList == null)
            return 0;
        else
            return mResultList.size();
    

    @Override
    public PlaceAutocomplete getItem(int position) 
        return mResultList.get(position);
    

    private ArrayList getPredictions(CharSequence constraint) 

        final ArrayList resultList = new ArrayList<>();

        // Create a new token for the autocomplete session. Pass this to FindAutocompletePredictionsRequest,
        // and once again when the user makes a selection (for example when calling fetchPlace()).
        AutocompleteSessionToken token = AutocompleteSessionToken.newInstance();


        // Use the builder to create a FindAutocompletePredictionsRequest.
        FindAutocompletePredictionsRequest request = FindAutocompletePredictionsRequest.builder()
                // Call either setLocationBias() OR setLocationRestriction().
                // .setLocationBias(bounds)
                .setLocationBias(mBounds)
                //.setCountry("au")
                //   .setTypeFilter(TypeFilter.ADDRESS)
                .setSessionToken(token)
                .setQuery(constraint.toString())
                .build();

        Task autocompletePredictions = placesClient.findAutocompletePredictions(request);

        // This method should have been called off the main UI thread. Block and wait for at most
        // 60s for a result from the API.
        try 
            Tasks.await(autocompletePredictions, 60, TimeUnit.SECONDS);
         catch (ExecutionException 

    @Override
    public Filter getFilter() 
        Filter filter = new Filter() 
            @Override
            protected FilterResults performFiltering(CharSequence constraint) 
                FilterResults results = new FilterResults();
                if (constraint != null) 
                    // Query the autocomplete API for the entered constraint
                    Log.d(TAG, "Before Prediction");
                    mResultList = getPredictions(constraint);
                    Log.d(TAG, "After Prediction");
                    if (mResultList != null) 
                        // Results
                        results.values = mResultList;
                        results.count = mResultList.size();
                    
                
                return results;
            

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) 
                if (results != null && results.count > 0) 
                    // The API returned at least one result, update the data.
                    notifyDataSetChanged();
                 else 
                    // The API did not return any results, invalidate the data set.
                    notifyDataSetInvalidated();
                
            
        ;
        return filter;
    

    public class PlaceAutocomplete 

        public CharSequence placeId;
        public CharSequence description;

        PlaceAutocomplete(CharSequence placeId, CharSequence description) 
            this.placeId = placeId;
            this.description = description;
        

        @Override
        public String toString() 
            return description.toString();
        
    



/* Now call adapter from activity */

 autoCompleteTextView = findViewById(R.id.autoCompleteTextView);
 autoCompleteTextView.setThreshold(3);

 //autoCompleteTextView.setOnItemClickListener(mAutocompleteClickListener);

mPlaceArrayAdapter = new PlaceArrayAdapter(this, R.layout.adapter_place_array, CURRENT_LOCATION_BONDS);

En Kotlin

TypeFilter.CITIES

ingrese la descripción de la imagen aquí

>

TypeFilter.ADDRESS

ingrese la descripción de la imagen aquí

  1. archivo de diseño de actividad

    
    
    
    
    
        
    
    
    
  2. En actividad

    class MainActivity :AppCompatActivity(), OnMapReadyCallback 
    
    private var mMap: GoogleMap? = null
    private var placeAdapter: PlaceArrayAdapter? = null
    private lateinit var mPlacesClient: PlacesClient
    
    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    
    
    override fun onPostCreate(savedInstanceState: Bundle?) 
        super.onPostCreate(savedInstanceState)
    
        Places.initialize(this, "GOOGLE_MAPS_KEY")
        mPlacesClient = Places.createClient(this)
    
        val mapFragment: SupportMapFragment? = supportFragmentManager.findFragmentById(R.id.mapLocation) as? SupportMapFragment
        mapFragment?.getMapAsync(this)
    
        placeAdapter = PlaceArrayAdapter(this, R.layout.layout_item_places, mPlacesClient)
        autoCompleteEditText.setAdapter(placeAdapter)
    
        autoCompleteEditText.onItemClickListener = AdapterView.OnItemClickListener  parent, _, position, _ ->
            val place = parent.getItemAtPosition(position) as PlaceDataModel
            autoCompleteEditText.apply 
                setText(place.fullText)
                setSelection(autoCompleteEditText.length())
            
        
    
    
    override fun onMapReady(p0: GoogleMap?) 
    
    
    
    
  • PlaceArrayAdapter

     class PlaceArrayAdapter(context: Context,val resource: Int, val mPlacesClient: PlacesClient) : ArrayAdapter(context, resource), Filterable 
    
     private var mContext : Context = context
     private var resultList = arrayListOf()
    
     override fun getCount(): Int 
         return when 
             resultList.isNullOrEmpty() -> 0
             else -> resultList.size
         
     
    
     override fun getItem(position: Int): PlaceDataModel? 
         return when 
             resultList.isNullOrEmpty() -> null
             else -> resultList[position]
         
     
    
     override fun getView(position: Int, convertView: View?, parent: ViewGroup): View 
         var view = convertView
         val viewHolder: ViewHolder
         if (view == null) 
             viewHolder = ViewHolder()
             view = LayoutInflater.from(context).inflate(resource, parent, false)
             viewHolder.description = view.findViewById(R.id.searchFullText) as TextView
             view.tag = viewHolder
          else 
             viewHolder = view.tag as ViewHolder
         
         bindView(viewHolder, resultList, position)
         return view!!
     
    
     private fun bindView(viewHolder: ViewHolder, place: ArrayList, position: Int) 
         if (!place.isNullOrEmpty()) 
             viewHolder.description?.text = place[position].fullText
         
     
    
     override fun getFilter(): Filter 
         return object : Filter() 
             override fun publishResults(constraint: CharSequence?, results: FilterResults?) 
                 if (results != null && results.count > 0) 
                     mContext.runOnUiThread 
                         notifyDataSetChanged()
                     
                  else 
                     notifyDataSetInvalidated()
                 
             
    
             override fun performFiltering(constraint: CharSequence?): FilterResults 
                 val filterResults = FilterResults()
                 if (constraint != null) 
                     resultList.clear()
                     val address = getAutocomplete(mPlacesClient, constraint.toString())
                     address?.let 
                         for (i in address.indices) 
                             val item = address[i]
                             resultList.add(PlaceDataModel(item.placeId, item.getFullText(StyleSpan(Typeface.BOLD)).toString()))
                         
                     
                     filterResults.values = resultList
                     filterResults.count = resultList.size
                 
                 return filterResults
             
         
     
    
     internal class ViewHolder 
         var description: TextView? = null
     
     
    
  • método getAutocomplete (puede agregar adaptador o extensión)

     fun getAutocomplete(mPlacesClient: PlacesClient, constraint: CharSequence): List 
       var list = listOf()
       val token = AutocompleteSessionToken.newInstance()
       val request = FindAutocompletePredictionsRequest.builder().setTypeFilter(TypeFilter.ADDRESS).setSessionToken(token).setQuery(constraint.toString()).build()
       val prediction = mPlacesClient.findAutocompletePredictions(request)
       try 
           Tasks.await(prediction, TASK_AWAIT, TimeUnit.SECONDS)
        catch (e: ExecutionException) 
           e.printStackTrace()
        catch (e: InterruptedException) 
           e.printStackTrace()
        catch (e: TimeoutException) 
           e.printStackTrace()
       
    
       if (prediction.isSuccessful) 
           val findAutocompletePredictionsResponse = prediction.result
         findAutocompletePredictionsResponse?.let 
               list = findAutocompletePredictionsResponse.autocompletePredictions
           
           return list
       
       return list
     
    
  • R.layout.layout_item_places

     
    
     
     
    

Cambiar este filtro:

  • abrir archivo MapExtention
  • método getAutocomplete
  • setTypeFilter (TypeFilter.CITIES)

#Demostración de Github

Te mostramos comentarios y valoraciones

Si tienes algún recelo y capacidad de beneficiar nuestro ensayo puedes realizar una nota y con gusto lo interpretaremos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *