Google 定位服务 API 的 Android 开发者指南
已发表: 2022-03-11在我们今天开发和使用的许多应用程序中,了解用户的位置是有用的信息。 有很多流行的基于位置的应用程序让我们的生活更轻松,并改变了我们使用这些服务的方式。 一个例子是广受欢迎的应用程序 Foursquare,经常去机构和“签到”的用户通常会赢得折扣。 优步,它可以帮助您以比普通出租车更低的价格通过手机打车。 这份名单很大,而且还在增长。
在本文中,我们将构建一个简单的 Android 应用程序,以使用 Android 的 Google Location Services API 确定用户的纬度和经度。 在开发 Android 应用程序时,有几种方法可以获取用户的位置。
包“android.location”
自 Android 首次引入以来,“android.location”包就已可用,它使我们能够访问位置服务。 这些服务允许应用程序获取设备地理位置的定期更新。
该软件包提供了两种获取位置数据的方法:
LocationManager.GPS_PROVIDER:使用卫星确定位置。 根据条件,此提供程序可能需要一段时间才能返回位置修复。
LocationManager.NETWORK_PROVIDER:根据附近蜂窝塔和 WiFi 接入点的可用性确定位置。 这比 GPS_PROVIDER 快。
当您在寻找用户位置时,您必须与这些提供商及其可用性进行比较。 理想情况下,您使用 NETWORK_PROVIDER 获得第一个位置,这可能不那么准确,但要快得多。 然后,您可以尝试通过使用 GPS_PROVIDER 侦听更好的位置修复来提高准确性。
此包提供的 API 相当低级,需要应用程序的开发人员处理更精细的细节,以确定何时请求位置数据并以优化的方式安排对 API 的调用。 为了改善开发人员使用基于位置的系统服务的体验并简化开发位置感知应用程序的过程,Google 引入了一种使用 Google Play 服务请求用户位置的新方法。 它提供了一个更简单的 API,具有更高的准确性、低功耗地理围栏等等。
谷歌定位服务 API
Google Location Services API,也称为 FusedLocationProviderApi,是 Google 推荐的获取用户位置的方法。 它根据我们的需要提供最佳精度。 与前一个 API 相比,使用此 API 的一些优点是:
简单性:与以前的 API 不同,您不再需要处理多个提供程序。 相反,您指定高级需求,例如“高精度”或“低功耗”,它将采取合适的方法。
可用性:让您的应用立即访问最佳、最近的已知位置。 通常这些信息很容易获得,您只需要索取即可。
电源效率:最大限度地减少应用程序的电源使用。
多功能性:满足广泛的需求,从前台使用 - 需要高度准确的位置数据,到后台使用 - 只需要定期更新位置,而对电源的影响可以忽略不计。
让我们使用这个 API 构建一个基于位置的 Android 应用程序。 为此,我们将使用 Google 推荐的用于 Android 应用程序开发的 IDE——Android Studio。 Android Studio 入门非常简单。 他们的网站非常详细地描述了涉及安装和配置 Android Studio 的过程,包括如何引导您的第一个 Android 应用程序进行开发。
Android Studio 应该让我们的事情变得超级简单。 但是,我们需要首先配置构建脚本并添加 Google Play 服务作为此应用程序的依赖项。 这可以通过如下修改“build.gradle”文件来完成:
dependencies { compile 'com.android.support:appcompat-v7:21.0.3' compile 'com.google.android.gms:play-services:6.5.87' // Add this line }
在我撰写本文时,可用的最新版 Google Play 服务是 6.5.87。 确保在开始之前始终检查可用的最新版本。 万一较晚的版本出现并且您决定为自己的项目更新它,请针对您支持的所有 Android 版本测试所有与位置相关的功能。
此时,我们应该可以开始为我们的应用程序做实际的工作了。
请求权限,配置AndroidManifest.xml
Android 具有特定的安全功能,可以防止任意应用程序请求精确的用户位置。 为了解决这个问题,我们需要编辑“AndroidManifest.xml”并添加我们需要的这个应用程序的权限:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
在此过程中,我们还应该定义用于此应用程序的 Google Play 服务版本:
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
检查 Google Play 服务的可用性
在访问 Google Play 服务提供的功能之前,我们必须检查设备是否安装了 Google Play 服务,并且该版本是我们打算使用的版本(6.5.87)。
private boolean checkGooglePlayServices(){ int checkGooglePlayServices = GooglePlayServicesUtil .isGooglePlayServicesAvailable(mContext); if (checkGooglePlayServices != ConnectionResult.SUCCESS) { /* * Google Play Services is missing or update is required * return code could be * SUCCESS, * SERVICE_MISSING, SERVICE_VERSION_UPDATE_REQUIRED, * SERVICE_DISABLED, SERVICE_INVALID. */ GooglePlayServicesUtil.getErrorDialog(checkGooglePlayServices, mContext, REQUEST_CODE_RECOVER_PLAY_SERVICES).show(); return false; } return true; }
此方法将检查 Google Play 服务,如果设备没有安装它(这种情况很少见,但我见过这种情况),它将打开一个带有相应错误的对话框并邀请用户安装/更新来自 Google Play 商店的 Google Play 服务。
用户完成“GooglePlayServicesUtil.getErrorDialog()”提供的解析后,会触发回调方法“onActivityResult()”,因此我们必须实现一些逻辑来处理该调用:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_RECOVER_PLAY_SERVICES) { if (resultCode == RESULT_OK) { // Make sure the app is not already connected or attempting to connect if (!mGoogleApiClient.isConnecting() && !mGoogleApiClient.isConnected()) { mGoogleApiClient.connect(); } } else if (resultCode == RESULT_CANCELED) { Toast.makeText(mContext, "Google Play Services must be installed.", Toast.LENGTH_SHORT).show(); finish(); } } }
访问 Google API
要访问 Google API,我们只需要再执行一步:创建 GoogleApiClient 的实例。 Google API 客户端为所有 Google Play 服务提供了一个公共入口点,并管理用户设备与每个 Google 服务之间的网络连接。 我们的第一步是启动连接。 我通常从活动的“onCreate”方法调用这段代码:
protected synchronized void buildGoogleApiClient() { mGoogleApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); }
通过链接一系列方法调用,我们指定了回调接口实现和我们想要使用的位置服务 API。 当与 Google Play 服务的连接成功、失败或挂起时,接口实现(在本例中为“this”)将接收对异步“connect()”方法的响应。 添加此代码后,我们的“MainActivity”应如下所示:
package com.bitwoo.userlocation; import android.content.Intent; import android.location.Location; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesUtil; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.location.LocationServices; public class MainActivity extends ActionBarActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener { private static int REQUEST_CODE_RECOVER_PLAY_SERVICES = 200; private GoogleApiClient mGoogleApiClient; private Location mLastLocation; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (checkGooglePlayServices()) { buildGoogleApiClient(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } private boolean checkGooglePlayServices() { int checkGooglePlayServices = GooglePlayServicesUtil .isGooglePlayServicesAvailable(this); if (checkGooglePlayServices != ConnectionResult.SUCCESS) { /* * google play services is missing or update is required * return code could be * SUCCESS, * SERVICE_MISSING, SERVICE_VERSION_UPDATE_REQUIRED, * SERVICE_DISABLED, SERVICE_INVALID. */ GooglePlayServicesUtil.getErrorDialog(checkGooglePlayServices, this, REQUEST_CODE_RECOVER_PLAY_SERVICES).show(); return false; } return true; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_RECOVER_PLAY_SERVICES) { if (resultCode == RESULT_OK) { // Make sure the app is not already connected or attempting to connect if (!mGoogleApiClient.isConnecting() && !mGoogleApiClient.isConnected()) { mGoogleApiClient.connect(); } } else if (resultCode == RESULT_CANCELED) { Toast.makeText(this, "Google Play Services must be installed.", Toast.LENGTH_SHORT).show(); finish(); } } } protected synchronized void buildGoogleApiClient() { mGoogleApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); } @Override public void onConnected(Bundle bundle) { } @Override public void onConnectionSuspended(int i) { } @Override public void onConnectionFailed(ConnectionResult connectionResult) { } }
然后在我们的“onStart”方法中调用“connect”方法并等待“onConnected”回调方法被调用:

@Override protected void onStart() { super.onStart(); if (mGoogleApiClient != null) { mGoogleApiClient.connect(); } }
“onConnected”方法如下所示:
@Override public void onConnected(Bundle bundle) { mLastLocation = LocationServices.FusedLocationApi.getLastLocation( mGoogleApiClient); if (mLastLocation != null) { Toast.makeText(this, "Latitude:" + mLastLocation.getLatitude()+", Longitude:"+mLastLocation.getLongitude(),Toast.LENGTH_LONG).show(); } }
连接 Google Play 服务时会触发此回调,这意味着到那时我们应该有最后一个已知位置。 但是,此位置可以为空(这种情况很少见,但并非不可能)。 在这种情况下,我建议收听位置更新,这将在接下来介绍。
监听位置更新
调用“getLastLocation”后,您可能希望从 Fused Location Provider 请求定期更新。 根据您的应用程序,这段时间可能很短也可能很长。 例如,如果您正在构建一个在用户开车时跟踪用户位置的应用程序,您将需要在短时间内侦听更新。 另一方面,如果您的应用程序是关于与他的朋友分享用户位置,您可能只需要偶尔请求一次位置。
创建请求非常简单——你可以在“onCreate”方法中调用这个方法:
protected void createLocationRequest() { mLocationRequest = new LocationRequest(); mLocationRequest.setInterval(20000); mLocationRequest.setFastestInterval(5000); mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); }
我们实例化一个新的 LocationRequest 对象。 将时间间隔设置为 20 秒(20000 毫秒)。 此外,我们将限制更新速率设置为 5 秒。 这告诉 API 每 20 秒(最好)提供一次更新,但如果在 5 秒内有可用的更改,它也应该提供。 最后,我们将优先级设置为“PRIORITY_HIGH_ACCURACY”,以及其他可用的优先级选项:PRIORITY_BALANCED_POWER_ACCURACY、PRIORITY_LOW_POWER、PRIORITY_NO_POWER。
一旦你建立了请求,你就可以在“onConnected()”方法被触发后开始监听位置更新:
protected void startLocationUpdates() { LocationServices.FusedLocationApi.requestLocationUpdates( mGoogleApiClient, mLocationRequest, this); }
现在剩下的就是实现回调方法来满足 LocationListener 接口:
public class MainActivity extends ActionBarActivity implements ConnectionCallbacks, OnConnectionFailedListener, LocationListener { // ... @Override public void onLocationChanged(Location location) { mLastLocation = location; Toast.makeText(this, "Latitude:" + mLastLocation.getLatitude()+", Longitude:"+mLastLocation.getLongitude(),Toast.LENGTH_LONG).show(); } }
停止监听更新
当您不再需要更新或用户离开您的应用程序时,显式停止侦听更新非常重要。 应从“onPause”回调中调用以下方法:
protected void stopLocationUpdates() { if (mGoogleApiClient != null) { LocationServices.FusedLocationApi.removeLocationUpdates( mGoogleApiClient, this); } }
... 并断开 Google API:
@Override protected void onStop() { super.onStop(); if (mGoogleApiClient != null) { mGoogleApiClient.disconnect(); } }
包起来
如您所见,在 Android 中实现位置感知应用程序背后的基本思想非常简单。 此外,使用简单易用且易于理解的可用 API,为 Android 构建基本的基于位置的应用程序应该是轻而易举的事。 我们在此处构建的小型示例应用程序旨在准确地展示这一点。 你可以在 GitHub 上找到完整的源代码。 请注意,为简单起见,应用程序不处理“onConnectionFailed”回调方法。
希望本教程能帮助您开始使用 Google 位置服务 API。