[英]Android- Google places api autocomplete with recycler view?
I am new to Android and trying to develop an app which has a map feature along with places auto complete.I am using google places Api to make my own custom autocomplete with a Recycler view.我是 Android 新手,正在尝试开发一个具有地图功能和地点自动完成功能的应用程序。我正在使用谷歌地点 Api 使用 Recycler 视图制作我自己的自定义自动完成功能。 Everything's working fine except the Recycler view displays prediction even after clearing the search edit text.一切正常,除了 Recycler 视图即使在清除搜索编辑文本后也会显示预测。 It occurs only when I delete the text fastly.If the text is changed slowly the recyler view is cleared otherwise not.I have tried around but couldn't find a solution.Posting my adapter and activity code.它仅在我快速删除文本时发生。如果文本更改缓慢,则回收器视图会被清除,否则不会。我已经尝试过但找不到解决方案。发布我的适配器和活动代码。 Any help will be appreciated任何帮助将不胜感激
public class AutoCompleteAdapter extends RecyclerView.Adapter<AutoCompleteAdapter.PredictionHolder> implements Filterable{
private static final String TAG = AutoCompleteAdapter.class.getSimpleName();
public interface PlaceAutoCompleteInterface{
void onPlaceClick(ArrayList<PlaceAutoComplete> mResultList,int position);
}
private ArrayList<PlaceAutoComplete> mResultList;
private Context mContext;
private int mLayout;
private GoogleApiClient mGoogleApiClient;
private AutocompleteFilter mPlaceFilter;
private LatLngBounds mBounds;
private PlaceAutoCompleteInterface mPlaceClickInterface;
public AutoCompleteAdapter(Context mContext,int mLayout,GoogleApiClient mGoogleApiClient,LatLngBounds mBounds,AutocompleteFilter mPlaceFilter,PlaceAutoCompleteInterface mPlaceClickInterface){
this.mContext=mContext;
this.mLayout=mLayout;
this.mGoogleApiClient=mGoogleApiClient;
this.mPlaceFilter=mPlaceFilter;
this.mBounds=mBounds;
this.mPlaceClickInterface=mPlaceClickInterface;
}
/**
* Setting Bounds for subsequent queries
*/
public void setmBounds(LatLngBounds mBounds){
this.mBounds=mBounds;
}
/*
Clear List items
*/
public void clearList(){
if(mResultList!=null && mResultList.size()>0){
mResultList.clear();
}
}
public static class PredictionHolder extends RecyclerView.ViewHolder{
private TextView mAddress1,mAddress2;
private LinearLayout mPredictionLayout;
public PredictionHolder(View holder){
super(holder);
mAddress1=(TextView)holder.findViewById(R.id.primary_address);
mAddress2=(TextView)holder.findViewById(R.id.secondary_address);
mPredictionLayout=(LinearLayout)holder.findViewById(R.id.prediction_layout);
}
}
/**
* Holder class for query result
*/
public class PlaceAutoComplete{
private CharSequence placeId;
private CharSequence placeAddress1,placeAddress2;
public PlaceAutoComplete(CharSequence placeId,CharSequence placeAddress1,CharSequence placeAddress2){
this.placeId=placeId;
this.placeAddress1=placeAddress1;
this.placeAddress2=placeAddress2;
}
public String getPlaceAddress1(){
return placeAddress1.toString();
}
public String getPlaceAddress2(){
return placeAddress2.toString();
}
public String getPlaceId(){
return placeId.toString();
}
}
@Override
public Filter getFilter() {
Filter filter=new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results=new FilterResults();
ArrayList<PlaceAutoComplete> queryResults;
if(constraint!=null && constraint.length()>0) {
queryResults = getAutoComplete(constraint);
if(queryResults!=null){
results.values = queryResults;
results.count = queryResults.size();
}
}
// The API successfully returned results.
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.
mResultList = (ArrayList<PlaceAutoComplete>) results.values;
notifyDataSetChanged();
}else{
// The API did not return any results, invalidate the data set.
clearList();
notifyDataSetChanged();
}
}
};
return filter;
}
/**
* Method to call API for each user input
* @param constraint User input character string
* @return ArrayList containing suggestion results
*/
private ArrayList<PlaceAutoComplete> getAutoComplete(CharSequence constraint){
if(mGoogleApiClient.isConnected()){
//Making a query and fetching result in a pendingResult
PendingResult<AutocompletePredictionBuffer> results= Places.GeoDataApi
.getAutocompletePredictions(mGoogleApiClient,constraint.toString(),mBounds,mPlaceFilter);
//Block and wait for 60s for a result
AutocompletePredictionBuffer autocompletePredictions=results.await(60, TimeUnit.SECONDS);
final Status status=autocompletePredictions.getStatus();
// Confirm that the query completed successfully, otherwise return null
if(!status.isSuccess()){
Log.e(TAG, "Error getting autocomplete prediction API call: " + status.toString());
autocompletePredictions.release();
return null;
}
Log.i(TAG, "Query completed. Received " + autocompletePredictions.getCount()
+ " predictions.");
// Copy the results into our own data structure, because we can't hold onto the buffer.
// AutocompletePrediction objects encapsulate the API response (place ID and description).
Iterator<AutocompletePrediction> iterator=autocompletePredictions.iterator();
ArrayList resultList=new ArrayList<>(autocompletePredictions.getCount());
while(iterator.hasNext()){
AutocompletePrediction prediction=iterator.next();
resultList.add(new PlaceAutoComplete(prediction.getPlaceId(),prediction.getPrimaryText(null),prediction.getSecondaryText(null)));
}
autocompletePredictions.release();
return resultList;
}else{
Log.e(TAG,"GoogleApiClient Not Connected");
return null;
}
}
@Override
public PredictionHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater mLayoutInflater=(LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View convertView=mLayoutInflater.inflate(mLayout,parent,false);
PredictionHolder predictionHolder=new PredictionHolder(convertView);
return predictionHolder;
}
@Override
public void onBindViewHolder(PredictionHolder holder, final int position) {
holder.mAddress1.setText(mResultList.get(position).getPlaceAddress1());
holder.mAddress2.setText(mResultList.get(position).getPlaceAddress2());
holder.mPredictionLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPlaceClickInterface.onPlaceClick(mResultList,position);
}
});
}
@Override
public int getItemCount() {
if(mResultList!=null){
return mResultList.size();
}else{
return 0;
}
}
public PlaceAutoComplete getItem(int position) {
return mResultList.get(position);
}
}
Activity code活动代码
public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, com.google.android.gms.location.LocationListener, AutoCompleteAdapter.PlaceAutoCompleteInterface {
private static final String TAG = MapsActivity.class.getSimpleName();
private static final int MY_PERMISSIONS_ACCESS_FINE_LOCATION = 1;
private static final int REQUEST_CHECK_SETTINGS = 2;
private static final LatLngBounds BOUNDS_INDIA = new LatLngBounds(
new LatLng(23.63936, 68.14712), new LatLng(28.20453, 97.34466));
private GoogleMap mMap;
private Button mSelectButton;
private TextView mPrimaryAddress, mSecondaryAddress;
private LinearLayout mAddressLayout;
private ImageButton mCurrentLocation;
private Location mLocation;
private LocationRequest mLocationRequest;
protected GoogleApiClient mGoogleApiClient;
private Double mLatitude, mLongitude;
private EditText mSearchText;
private RecyclerView mRecyclerView;
private AutoCompleteAdapter mAdapter;
private ImageView mCustomMarker;
private static boolean sCameraMoved = true;
private AddressResultReceiver mAddressResultReceiver;
@Override
protected void onStop() {
mGoogleApiClient.disconnect();
super.onStop();
}
@Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
if (isGooglePlayServicesAvailable()) {
buildGoogleAPiClient();
} else {
Log.e(TAG, "Google Play Services not available");
}
createLocationRequest();
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
mSelectButton = (Button) findViewById(R.id.select_button);
mPrimaryAddress = (TextView) findViewById(R.id.firstAddress);
mSecondaryAddress = (TextView) findViewById(R.id.secondAddress);
mAddressLayout = (LinearLayout) findViewById(R.id.address_layout);
mCurrentLocation = (ImageButton) findViewById(R.id.get_current_location);
mCustomMarker = (ImageView) findViewById(R.id.map_custom_marker);
mSearchText = (EditText) findViewById(R.id.search_box);
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
MapFragment mapFragment = ((MapFragment)getFragmentManager().findFragmentById(R.id.map));
mapFragment.getMapAsync(this);
isGpsOn();
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(layoutManager);
mAdapter = new AutoCompleteAdapter(this, R.layout.layout_recommendation, mGoogleApiClient, BOUNDS_INDIA, null, this);
mRecyclerView.setAdapter(mAdapter);
mAddressResultReceiver = new AddressResultReceiver(null);
mSearchText.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
mSearchText.setCursorVisible(true);
return false;
}
});
mSearchText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (!s.equals("") && mGoogleApiClient.isConnected()) {
mAdapter.getFilter().filter(s.toString());
} else if (!mGoogleApiClient.isConnected()) {
Log.e(TAG, "API NOT CONNECTED");
}
}
@Override
public void afterTextChanged(Editable s) {
if(s.toString().equals("")){
mAdapter.getFilter().filter(null);
}
}
});
mCurrentLocation.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
isGpsOn();
}
});
mSelectButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mLongitude != null && mLongitude != null) {
Intent resultIntent = new Intent();
resultIntent.putExtra("address1", mPrimaryAddress.getText().toString());
resultIntent.putExtra("address2", mSecondaryAddress.getText().toString());
resultIntent.putExtra("latitude", mLatitude);
resultIntent.putExtra("longitude", mLongitude);
setResult(Activity.RESULT_OK, resultIntent);
MapsActivity.this.finish();
} else {
Toast.makeText(getBaseContext(), "Select a location", Toast.LENGTH_SHORT).show();
}
}
});
}
/**
* Method to initialize LocationRequest
*/
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(10000);
mLocationRequest.setFastestInterval(5000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY | LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
}
// Function to build the Google Api Client..
protected synchronized void buildGoogleAPiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addOnConnectionFailedListener(this)
.addConnectionCallbacks(this)
.addApi(LocationServices.API)
.addApi(Places.GEO_DATA_API)
.build();
}
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(20.5937, 78.9629), 4.0f));
}
@Override
public void onPlaceClick(ArrayList<AutoCompleteAdapter.PlaceAutoComplete> mResultList, int position) {
if (mResultList != null) {
try {
String placeId = String.valueOf(mResultList.get(position).getPlaceId());
mSearchText.setText("");
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mSearchText.getWindowToken(), 0);
mSearchText.setCursorVisible(false);
PendingResult<PlaceBuffer> placeResult = Places.GeoDataApi.getPlaceById(mGoogleApiClient, placeId);
placeResult.setResultCallback(new ResultCallback<PlaceBuffer>() {
@Override
public void onResult(@NonNull PlaceBuffer places) {
if (!places.getStatus().isSuccess()) {
// Request did not complete successfully
Log.e(TAG, "Place query did not complete. Error: " + places.getStatus().toString());
places.release();
return;
}
Place place = places.get(0);
mLatitude = place.getLatLng().latitude;
mLongitude = place.getLatLng().longitude;
mPrimaryAddress.setText(place.getName());
mSecondaryAddress.setText(place.getAddress());
mAddressLayout.setVisibility(View.VISIBLE);
sCameraMoved = false;
loadMap();
places.release();
}
});
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, e.toString());
}
}
}
/**
* Method to display the location on Map
*/
public void loadMap() {
if (mLatitude != null && mLongitude != null) {
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(new LatLng(mLatitude, mLongitude)) // Sets the center of the map to location user
.zoom(18) // Sets the zoom// Sets the tilt of the camera to 30 degrees
.build(); // Creates a CameraPosition from the builder
mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
mCustomMarker.setVisibility(View.VISIBLE);
mMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
@Override
public void onCameraIdle() {
Location location = new Location("");
if (sCameraMoved) {
mLatitude = mMap.getCameraPosition().target.latitude;
mLongitude = mMap.getCameraPosition().target.longitude;
location.setLatitude(mLatitude);
location.setLongitude(mLongitude);
convertLocationToAddress(location);
}
sCameraMoved = true;
}
});
}
}
@Override
public void onConnected(@Nullable Bundle bundle) {
startLocationUpdates();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_ACCESS_FINE_LOCATION: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mCurrentLocation.setVisibility(View.VISIBLE);
} else {
mCurrentLocation.setVisibility(View.GONE);
}
return;
}
}
}
protected void startLocationUpdates() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
} else {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_ACCESS_FINE_LOCATION);
Log.d(TAG, "Permission Not Granted");
}
} else {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
}
}
/**
* Method to stop the regular location updates
*/
protected void stopLocationUpdates() {
if (mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient, this);
}
}
@Override
protected void onResume() {
super.onResume();
if (mGoogleApiClient.isConnected()) {
startLocationUpdates();
}
}
@Override
protected void onPause() {
super.onPause();
stopLocationUpdates();
}
@Override
public void onConnectionSuspended(int i) {
Log.e(TAG, "Connection Suspended");
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
Log.e(TAG, "Connection Failed");
}
@Override
public void onLocationChanged(Location location) {
mLocation = location;
}
/**
* Method to get current location and do reverse geocoding of the location
*/
private void getCurrentLocationAddress() {
if (mLocation != null) {
mLatitude = mLocation.getLatitude();
mLongitude = mLocation.getLongitude();
convertLocationToAddress(mLocation);
loadMap();
}
}
/**
* Method to check if google play services are enabled or not
*
* @return boolean status
*/
public boolean isGooglePlayServicesAvailable() {
GoogleApiAvailability googleApiAvailability = GoogleApiAvailability.getInstance();
int status = googleApiAvailability.isGooglePlayServicesAvailable(this);
if (status != ConnectionResult.SUCCESS) {
if (googleApiAvailability.isUserResolvableError(status)) {
googleApiAvailability.getErrorDialog(this, status, 2404).show();
}
return false;
}
return true;
}
/**
* Method to check if GPS is on or not
*/
private void isGpsOn() {
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest);
PendingResult<LocationSettingsResult> result =
LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient, builder.build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
@Override
public void onResult(@NonNull LocationSettingsResult locationSettingsResult) {
final Status status = locationSettingsResult.getStatus();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
getCurrentLocationAddress();
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try {
status.startResolutionForResult(
MapsActivity.this,
REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "Exception : " + e);
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
Log.e(TAG, "Location settings are not satisfied.");
break;
}
}
});
}
/**
* Method to convert latitude and longitude to address via reverse-geocoding
*/
private void convertLocationToAddress(Location location) {
Intent intent = new Intent(this, GeoCoderIntentService.class);
intent.putExtra(Constants.RECEIVER, mAddressResultReceiver);
intent.putExtra(Constants.LOCATION_DATA_EXTRA, location);
startService(intent);
}
private class AddressResultReceiver extends ResultReceiver {
public AddressResultReceiver(Handler handler) {
super(handler);
}
protected void onReceiveResult(final int resultCode, Bundle resultData) {
final String address1 = resultData.getString(Constants.ADDRESS_DATA_KEY1);
final String address2 = resultData.getString(Constants.ADDRESS_DATA_KEY2);
runOnUiThread(new Runnable() {
@Override
public void run() {
if (resultCode == Constants.SUCCESS_RESULT) {
mPrimaryAddress.setText(address1);
mSecondaryAddress.setText(address2);
mAddressLayout.setVisibility(View.VISIBLE);
} else {
Log.e(TAG, "Error while fetching data");
mLatitude = mLongitude = null;
mPrimaryAddress.setText(address1);
mSecondaryAddress.setText("");
}
}
});
}
}
}
Try to change your code like below,尝试更改您的代码,如下所示,
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (!s.equals("")) {
if(mGoogleApiClient.isConnected()){
mAdapter.getFilter().filter(s.toString());
}else{
Log.e(TAG, "API NOT CONNECTED");
}
} else {
mAdapter.mResultList.clear();//make mResultList as public
mAdapter.notifyDataSetChanged();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.