Google Play服务:使用Places API

2015年3月,Google发布了Android版Places API,作为Google Play服务的一部分。 该API使开发人员可以从Google访问大量信息,从而通过使用地点的名称和信息(而不是一组坐标)为用户提供针对其当前位置的量身定制的体验。

在本教程中,您将学习如何向用户展示Place Picker组件,如何使用Places API猜测用户的当前位置,通过其ID搜索位置,以及允许用户在文本字段中键入内容以显示它们具有预测结果。

1.设置

如果您还没有Android公共API密钥,则需要为Android应用程序创建公共Google API密钥。 您可以通过访问Google的开发人员控制台进行此操作 。 Google的文档中提供了基于签名证书和程序包名称创建密钥的说明 ,这些说明不在本文的讨论范围之内。

创建密钥后,搜索Places API并将其设置为enabled。 在每24小时内可以发送多少请求的情况下,对Places API的某些调用受到限制。 在撰写本文时,不具有计费配置文件的帐户最多可以发送1,000个请求,而具有计费配置文件的帐户可以发送150,000个请求。 如果您需要更多,则可以提交请求以按照“ 使用限制”文档中的说明增加此限制。

准备使用API​​密钥后,就可以开始进行演示项目了。 在Android Studio中创建一个项目,并将支持的最低SDK版本设置为至少9。这是使用Google Play服务的最低要求。

Android Studio创建Hello World模板项目后,打开build.gradle文件,并在“ dependencies节点下,添加所需的Play Services 7.0依赖项。 这是撰写本文时的最新版本,但是您可以通过查看Google文档来验证最新版本。

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.0.0'
    compile 'com.google.android.gms:play-services:7.0.0'
}

接下来,打开AndroidManifest.xml ,为项目添加所需的权限,并声明应用程序需要OpenGL版本2。




您在清单中要做的最后一件事是添加两个标签,以在标签内为该设置gms版本和API密钥。


完成清单后,就可以开始编写代码了。 由于这是Play Services的组件,因此您需要初始化GoogleApiClient并在Activity的生命周期内进行连接/断开连接。 我们在Activity类的onCreateonStartonStop方法中执行此操作。

@Override
protected void onCreate( Bundle savedInstanceState ) {
    //--Snippet
    mGoogleApiClient = new GoogleApiClient
            .Builder( this )
            .enableAutoManage( this, 0, this )
            .addApi( Places.GEO_DATA_API )
            .addApi( Places.PLACE_DETECTION_API )
            .addConnectionCallbacks( this )
            .addOnConnectionFailedListener( this )
            .build();
}

@Override
protected void onStart() {
    super.onStart();
    if( mGoogleApiClient != null )
        mGoogleApiClient.connect();
}

@Override
protected void onStop() {
    if( mGoogleApiClient != null && mGoogleApiClient.isConnected() ) {
        mGoogleApiClient.disconnect();
    }
    super.onStop();
}

2.使用“地点选择器”小部件

地点选择器小部件是Play服务提供的用户界面组件,可让用户查看其周围区域的地图。 该组件包括您的应用可以使用的附近地点的列表。 通过使用此组件,您可以遵循一个标准设计,您的用户将知道如何与之交互,同时可以节省开发时间。

Google Play服务:使用Places API_第1张图片

要使用位置选择器,您需要创建一个意图并监听Activity结果以检索用户选择的位置。 以下方法显示了如何启动此Activity

private void displayPlacePicker() {
    if( mGoogleApiClient == null || !mGoogleApiClient.isConnected() )
        return;

    PlacePicker.IntentBuilder builder = new PlacePicker.IntentBuilder();
    
    try {
        startActivityForResult( builder.build( getApplicationContext() ), PLACE_PICKER_REQUEST );
    } catch ( GooglePlayServicesRepairableException e ) {
            Log.d( "PlacesAPI Demo", "GooglePlayServicesRepairableException thrown" );
    } catch ( GooglePlayServicesNotAvailableException e ) {
        Log.d( "PlacesAPI Demo", "GooglePlayServicesNotAvailableException thrown" );
    }
}

PlacePicker.IntentBuilder用于创建将用于启动位置选择器的Intent 它还有一个可用的方法setLatLngBounds ,它使您可以放置​​从西南角到东北角的地理边界,以控制搜索区域。

可以使用PlacePicker.IntentBuilderbuild方法来build PlacePicker.IntentBuilder并使用ActivitystartActivityForResult方法来启动Intent 应当注意,使用build方法确实有可能GooglePlayServicesRepairableExceptionGooglePlayServicesNotAvailableException异常,因此应使用标准try / catch块检查这些异常,并在发生异常时对其进行适当处理。

如果用户从位置选择器列表中选择一个位置,则该Place对象将被打包到一个Intent并发送回调用方Activity 使用PlacePicker.getPlace方法,可以从返回的Intent提取Place数据。

protected void onActivityResult( int requestCode, int resultCode, Intent data ) {
    if( requestCode == PLACE_PICKER_REQUEST && resultCode == RESULT_OK ) {
        displayPlace( PlacePicker.getPlace( data, this ) );
    }
}

提取Place对象后,可以将其视为模型对象以在您的应用程序中显示或使用。

private void displayPlace( Place place ) {
    if( place == null )
        return;

    String content = "";
    if( !TextUtils.isEmpty( place.getName() ) ) {
        content += "Name: " + place.getName() + "\n";
    }
    if( !TextUtils.isEmpty( place.getAddress() ) ) {
        content += "Address: " + place.getAddress() + "\n";
    }
    if( !TextUtils.isEmpty( place.getPhoneNumber() ) ) {
        content += "Phone: " + place.getPhoneNumber();
    }

    mTextView.setText( content );
}
Google Play服务:使用Places API_第2张图片

3.查找用户的当前位置

Places API的另一个有趣功能是,您可以使用它来猜测用户当前是否在列出的位置。 API也将提供一种可能性,以便您可以就应用程序应如何与用户交互做出明智的决定。 应该注意的是,这是API的功能之一,需要针对您分配的使用情况提出请求。

要检测用户的位置,您将需要使用Places.PlacesDetectionApi.getCurrentPlace方法创建一个PendingIntent ,该对象将随PlaceLikelihoodBuffer对象一起返回。 使用ResultCallBack ,您可以从缓冲区中取出第一个(也是最有可能的)位置,并在应用程序中使用它。

如果您的应用需要更多信息,则可以通过循环从缓冲区中提取其他PlaceLikelihood项目。 在每个PlaceLikelihood对象中,该位置是用户当前所在位置的可能性作为从0.01.0的浮点值传回,其中1.0几乎可以保证匹配。 不要忘记在PlaceLikelihoodBuffer上调用release ,以避免任何内存泄漏。

private void guessCurrentPlace() {
    PendingResult result = Places.PlaceDetectionApi.getCurrentPlace( mGoogleApiClient, null );
    result.setResultCallback( new ResultCallback() {
        @Override
        public void onResult( PlaceLikelihoodBuffer likelyPlaces ) {

            PlaceLikelihood placeLikelihood = likelyPlaces.get( 0 );
            String content = "";
            if( placeLikelihood != null && placeLikelihood.getPlace() != null && !TextUtils.isEmpty( placeLikelihood.getPlace().getName() ) )
                content = "Most likely place: " + placeLikelihood.getPlace().getName() + "\n";
            if( placeLikelihood != null )
                content += "Percent change of being there: " + (int) ( placeLikelihood.getLikelihood() * 100 ) + "%";
            mTextView.setText( content );

            likelyPlaces.release();
        }
    });
}

4.预测地点

我们将在本教程中讨论的下一个也是最复杂的主题是在用户输入搜索查询时向他们预测并显示位置。 同样,此API调用也计入API的使用限制。 但是,这对于提高您的应用程序的可用性非常宝贵。

Google Play服务:使用Places API_第3张图片

对于本教程的这一部分,您将在应用程序中使用AutoCompleteTextView和自定义适配器来键入进行预测的地点的名称。 几乎所有工作都在适配器中完成。 但是,我们需要将对GoogleApiClient的引用GoogleApiClient给适配器,以使其能够访问API。

这可以在标准的GoogleApiClient回调onConnected ,我们可以在onStop中删除客户端的实例,其中mAdapter是我们的自定义AdapterAutoCompleteAdapter的实例。

@Override
protected void onStop() {
    if( mGoogleApiClient != null && mGoogleApiClient.isConnected() ) {
        mAdapter.setGoogleApiClient( null );
        mGoogleApiClient.disconnect();
    }
    super.onStop();
}

@Override
public void onConnected( Bundle bundle ) {
    if( mAdapter != null )
        mAdapter.setGoogleApiClient( mGoogleApiClient );
}

要在用户在AutoCompleteTextView输入新字母时触发API调用,您需要重写ArrayAdaptergetFilter方法。 每当用户更改与适配器关联的视图的内容时,都会触发此方法。 它允许您更改AutoCompleteTextView适配器的内容。 在以下示例中, constraints是视图的内容。

@Override
public Filter getFilter() {
    return new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {

            if( mGoogleApiClient == null || !mGoogleApiClient.isConnected() ) {
                Toast.makeText( getContext(), "Not connected", Toast.LENGTH_SHORT ).show();
                return null;
            }

            clear();

            displayPredictiveResults( constraint.toString() );

            return null;
        }

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            notifyDataSetChanged();
        }
    };
}

displayPredictiveResults方法是与API进行实际交互的地方。 可以使用一些不同的对象来自定义您的预测。

第一个是LatLngBounds对象,该对象创建一个从西南点到东北点的正方形边界以定位查询。 如果传递了null而不是初始化的LatLngBounds对象,则不会对查询施加任何地理限制。

LatLngBounds bounds = new LatLngBounds( new LatLng( 39.906374, -105.122337 ), new LatLng( 39.949552, -105.068779 ) );

您可以创建以自定义查询的第二个对象是API请求的过滤器。 Places AutoCompletePredictions调用的过滤器是代表不同类型过滤器的Integer对象的列表。 此时,只能将一种过滤器类型应用于查询。 可接受的值可以在文档中找到。 如果Integer列表为空或传递了null ,则返回所有结果类型。

准备好发出请求后,可以使用Places.GeoDataApi.getAutocompletePredictions方法返回PendingIntent ,可以将其与ResultCallback关联以显示返回的信息。

重要的是要注意,代表来自缓冲区的AutoCompletePrediction对象的自定义对象用于将数据存储在ArrayAdapter 否则,一旦释放缓冲区,就会抛出IllegalArgumentsException异常,这对于避免内存泄漏至关重要。

private void displayPredictiveResults( String query )
{
    //Southwest corner to Northeast corner.
    LatLngBounds bounds = new LatLngBounds( new LatLng( 39.906374, -105.122337 ), new LatLng( 39.949552, -105.068779 ) );

    //Filter: https://developers.google.com/places/supported_types#table3
    List filterTypes = new ArrayList();
    filterTypes.add( Place.TYPE_ESTABLISHMENT );

    Places.GeoDataApi.getAutocompletePredictions( mGoogleApiClient, query, bounds, AutocompleteFilter.create( filterTypes ) )
        .setResultCallback (
            new ResultCallback() {
                @Override
                public void onResult( AutocompletePredictionBuffer buffer ) {

                    if( buffer == null )
                        return;

                    if( buffer.getStatus().isSuccess() ) {
                        for( AutocompletePrediction prediction : buffer ) {
                            //Add as a new item to avoid IllegalArgumentsException when buffer is released
                            add( new AutoCompletePlace( prediction.getPlaceId(), prediction.getDescription() ) );
                        }
                    }

                    //Prevent memory leak by releasing buffer
                    buffer.release();
                }
            }, 60, TimeUnit.SECONDS );
}

AutoCompleteAdapter的内容使用android.R.layout.simple_list_item_1布局和getView标准ViewHolder模式显示。

@Override
public View getView( int position, View convertView, ViewGroup parent ) {
    ViewHolder holder;

    if( convertView == null ) {
        holder = new ViewHolder();
        convertView = LayoutInflater.from( getContext() ).inflate( android.R.layout.simple_list_item_1, parent, false  );
        holder.text = (TextView) convertView.findViewById( android.R.id.text1 );
        convertView.setTag( holder );
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    holder.text.setText( getItem( position ).getDescription() );

    return convertView;
}

当从该列表中单击一个项目时,所选位置的ID Place传递到onItemClickedListener并搜索以显示。

5.通过ID搜索地点

本教程的最后一部分将介绍根据其ID查找Place对象。 通过创建PendingIntent并与返回的缓冲区进行交互以检索位置,此工作与其他API调用类似。 像您使用过的其他缓冲区对象一样, PlaceBuffer必须调用release以避免任何内存泄漏。

private void findPlaceById( String id ) {
    if( TextUtils.isEmpty( id ) || mGoogleApiClient == null || !mGoogleApiClient.isConnected() )
        return;

   Places.GeoDataApi.getPlaceById( mGoogleApiClient, id ) .setResultCallback( new ResultCallback() {
       @Override
       public void onResult(PlaceBuffer places) {
           if( places.getStatus().isSuccess() ) {
               Place place = places.get( 0 );
               displayPlace( place );
               mPredictTextView.setText( "" );
               mAdapter.clear();
           }

           //Release the PlaceBuffer to prevent a memory leak
           places.release();
       }
   } );
}

结论

Places API是一个功能强大的工具,可让您的应用知道用户的位置,从而为他们提供上下文信息。 在本教程中,您学习了如何使用“位置选择器”组件,猜测用户的位置,在搜索时向他们显示预测结果以及根据给定的ID查找位置。 除了此处介绍的主题之外,还可以向Google提交新的地点,以帮助扩展API可以访问的信息。

翻译自: https://code.tutsplus.com/articles/google-play-services-using-the-places-api--cms-23715

你可能感兴趣的:(Google Play服务:使用Places API)