在Google Places API中搜索特定城市内的位置

12

我正在使用Google Places API来过滤一个特定城市内的结果。我可以过滤出结果,但它也显示了该城市之外的结果。例如:如果我设置DELHI城市的LatLngBounds并搜索城市NEWYORK中的某个位置,则也会给我显示NEWYORK城市的结果(但NEWYORK的LatLng不在DELHI范围内)。

我如何将搜索结果限制在特定城市内?

这是我的PlaceAutoCompleteAdapter类。

import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.common.data.DataBufferUtils;
import com.google.android.gms.location.places.AutocompleteFilter;
import com.google.android.gms.location.places.AutocompletePrediction;
import com.google.android.gms.location.places.AutocompletePredictionBuffer;
import com.google.android.gms.location.places.Places;
import com.google.android.gms.maps.model.LatLngBounds;


import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.concurrent.TimeUnit;

public class PlaceAutocompleteAdapter
        extends ArrayAdapter<AutocompletePrediction> implements Filterable {


    private ArrayList<AutocompletePrediction> mResultList;
    private GoogleApiClient mGoogleApiClient;
    private LatLngBounds mBounds;
    private AutocompleteFilter mPlaceFilter;

    public PlaceAutocompleteAdapter(Context context, GoogleApiClient googleApiClient,
            LatLngBounds bounds, AutocompleteFilter filter) {
        super(context,R.layout.simple_expandble_text_view_item, R.id.text1);
        mGoogleApiClient = googleApiClient;
        mBounds = bounds;
        mPlaceFilter = filter;
    }

    public void setBounds(LatLngBounds bounds) {
        mBounds = bounds;
    }

    @Override
    public int getCount() {
        return mResultList.size();
    }

    @Override
    public AutocompletePrediction getItem(int position) {
        return mResultList.get(position);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View row = super.getView(position, convertView, parent);
        AutocompletePrediction item = getItem(position);

        TextView textView1 = (TextView) row.findViewById(R.id.text1);
        textView1.setText(item.getDescription());
        return row;
    }

    @Override
    public Filter getFilter() {
        return new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults results = new FilterResults();
                if (constraint != null) {
                    mResultList = getAutocomplete(constraint);
                    if (mResultList != null) {
                        results.values = mResultList;
                        results.count = mResultList.size();
                    }
                }
                return results;
            }

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                if (results != null && results.count > 0) {
                    notifyDataSetChanged();
                } else {
                    notifyDataSetInvalidated();
                }
            }

            @Override
            public CharSequence convertResultToString(Object resultValue) {
                if (resultValue instanceof AutocompletePrediction) {
                    return ((AutocompletePrediction) resultValue).getDescription();
                } else {
                    return super.convertResultToString(resultValue);
                }
            }
        };
    }

    private ArrayList<AutocompletePrediction> getAutocomplete(CharSequence constraint) {
        if (mGoogleApiClient.isConnected()) {
            PendingResult<AutocompletePredictionBuffer> results =
                    Places.GeoDataApi
                            .getAutocompletePredictions(mGoogleApiClient, constraint.toString(),
                                    mBounds, mPlaceFilter);
            AutocompletePredictionBuffer autocompletePredictions = results
                    .await(60, TimeUnit.SECONDS);

            final Status status = autocompletePredictions.getStatus();
            if (!status.isSuccess()) {
                Toast.makeText(getContext(), "Error contacting API: " + status.toString(),
                        Toast.LENGTH_SHORT).show();
                autocompletePredictions.release();
                return null;
            }
            return DataBufferUtils.freezeAndClose(autocompletePredictions);
        }
        return null;
    }
}

你能发布你的代码吗? - Nigam Patro
我已经包含了我的代码。 - Navin Gupta
你能否输出一下你正在使用的mBounds吗?我的意思是在你编写的getAutocomplete函数中,真正记录mBounds值的日志调用。 - N Dorigatti
是的,我在这里获取当前的mBounds。 - Navin Gupta
2个回答

4

查看文档:

public abstract PendingResult getAutocompletePredictions (GoogleApiClient client, String query, LatLngBounds bounds, AutocompleteFilter filter) 基于地点的名称和地址,返回查询的自动完成预测结果。更多信息请参见开发人员指南。

此方法执行网络查找。

使用此方法受到配额限制。有关详细信息,请参阅使用限制。

参数

query 要获取自动完成预测的查询字符串。

bounds 地理边界。如果存在,则返回的预测结果将偏向该区域内的地点。

filter 用于限制返回的预测结果的筛选器。如果为 null,则使用没有约束的筛选器。

"bounds" 的描述是返回偏向预测结果。因此,这些结果不会被过滤,而是基于这个边界进行偏置。这意味着边界内的结果应该具有更高的优先级,但那些结果不会是唯一的结果。

更新

截至2018年4月,谷歌增加了自动完成预测中如何处理边界的选项。现在您可以使用GeoDataClient类的getAutocompletePredictions()方法,并提供boundsMode参数。
有关详细信息,请参见https://dev59.com/Qpzha4cB1Zd3GeqPJ8KI#50134855

但是怎么样才能得到精确的结果呢?我是否需要手动筛选结果? - Navin Gupta
如果您想获取过滤后的结果(仅限于边界框),则必须使用位置和边界框手动进行筛选。查看API时,您无法获取每个地方的LatLng位置,而是只能获取ID,因此每个结果都需要一个api请求来获取ID的Place对象(1000个结果= 1000 api调用!),这不是一个好的解决方案。如果您仍然想这样做,请检查场所的LatLng位置是否在边界框内;请检查边界框相对于场所位置的纬度和经度最小/最大值。 - N Dorigatti

2
您编写的代码是正确的。我以前也做过类似的事情,但没有尝试使用边界。我经过边界检查并阅读了文档,发现它会提供有偏差的结果,这意味着它会优先考虑给定范围内的结果。
以下是文档链接:

https://developers.google.com/places/android-api/autocomplete


嗨,Nigam Patro,感谢您的回答。在发布问题之前,我已经阅读了Google文档,但我正在寻找一种将结果限制在我的范围内的方法。有什么办法可以实现这一点吗?感谢您的时间。 - Navin Gupta

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接