Android开发人员的Google定位服务API指南

本文概述

在我们今天开发和使用的许多应用程序中, 了解用户的位置是有用的信息。有许多流行的基于位置的应用程序使我们的生活变得更轻松, 并且改变了我们使用这些服务的方式。一个示例是广受欢迎的应用程序Foursquare, 在该应用程序中, 经常光顾一家公司并”签到”的用户通常会获得折扣。优步(Uber), 可帮助你以比普通出租车更低的费率从手机上乘车。列表很大, 而且还在增长。

定位服务API

在本文中, 我们将构建一个简单的Android应用程序, 以使用Android的Google定位服务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, 具有更高的准确性, 低功耗的地理围栏等等。

Google定位服务API

Google定位服务API(也称为FusedLocationProviderApi)是Google推荐的获取用户位置的方法。它可以根据我们的需求提供最佳的准确性。与上一个相比, 使用此API的一些优点是:

  • 简便性:与以前的API不同, 你不再需要与多个提供程序打交道。相反, 你可以指定高层需求, 例如”高精度”或”低功耗”, 这将采用合适的方法。

  • 可用性:可让你的应用立即访问最近的最佳已知位置。通常, 此信息是随时可用的, 你只需要索取即可。

  • 节能:最大限度地减少应用程序的功耗。

  • 多功能性:满足广泛的需求, 从前景使用-需要高度精确的位置数据, 到后台使用-仅需要定期位置更新, 而对功率的影响却可以忽略不计。

让我们使用此API构建一个基于位置的Android应用程序。为此, 我们将使用Google建议的IDE进行Android应用程序开发-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商店中的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();
}

通过链接一系列方法调用, 我们指定了回调接口实现和我们要使用的Location Service 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”后, 你可能需要向融合位置提供者请求定期更新。根据你的应用程序, 此时间段可能短或长。例如, 如果你要构建一个在用户开车时跟踪其位置的应用程序, 则需要间隔很短的时间监听更新。另一方面, 如果你的应用程序要与他的朋友共享用户位置, 则可能只需要偶尔请求一次位置。

创建请求非常简单-你可以在” 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);
	}
}

…并断开Goog​​le API的连接:

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

本文总结

如你所见, 在Android中实现位置感知应用程序的基本思想非常简单。此外, 借助易于使用和易于理解的可用API, 为Android构建基于位置的基本应用程序应该是轻而易举的事。我们在此处构建的小样本应用程序旨在证明这一点。你可以在GitHub上找到完整的源代码。请注意, 为简单起见, 应用程序未处理” onConnectionFailed”回调方法。

希望本教程可以帮助你开始使用Google Location Services API。

微信公众号
手机浏览(小程序)
0
分享到:
没有账号? 忘记密码?