注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好。
原文链接: http://developer.android.com/training/location/retrieve-current.html
地点服务自动维护用户当前的地点,所以你的应用所要做的事情就是在需要时去获取它。地点的精确度是基于你所申请的地点查询权限,以及当前设备上激活的的位置传感器。
地点服务会通过定位客户端(定位服务类的一个实例:
LocationClient
),将当前的位置发送给你的应用,所有地点信息的请求都通过这一客户端。
Note:
在你开始这节课之前,请确定你的开发环境和测试设备都已经配置正确。可以阅读 Setup 获取更多这方面的信息。
一). 指定应用权限
使用位置服务的应用必须请求定位权限。Android有两个定位权限: ACCESS_COARSE_LOCATION (粗定位)和 ACCESS_FINE_LOCATION (精定位)。你所选择的权限决定了定位的精度。如果你只请求粗定位,位置服务所范围的地点信息大致会精确到一个城市街区。
如果请求 ACCESS_FINE_LOCATION ,它也暗含了 ACCESS_COARSE_LOCATION 的权限。
例如,要添加
ACCESS_COARSE_LOCATION
,将下面的代码作为
<manifest>
元素的子元素:
<
uses-permission
android:name
="android.permission.ACCESS_COARSE_LOCATION"
/>
二). 检查Google Play服务
位置服务是Google Play服务APK的其中一部分。由于用户设备的状态时难以预料的,你应该一直在你尝试连接定位服务之前,检查APK是否已经安装。要检查APK是否安装,可以调用
GooglePlayServicesUtil.isGooglePlayServicesAvailable()
,它会返回一个整形的结果码,其含义可以参阅:
ConnectionResult
。如果你遇到了一个错误,可以调用
GooglePlayServicesUtil.getErrorDialog()
,来获取一个本地的对话框,引导用户执行正确地行为,之后将这一对话框显示在一个
DialogFragment
上。这一对话框可能允许用户解决当前的问题,此时Google Play服务会发回一个结果到你的activity中。要处理这一结果,需要覆写
onActivityResult()
方法。
由于你一直需要在你的代码多个地方检查Google Play服务,所以应该定义一个方法将检查行为进行封装,之后在每次连接尝试之前进行检查。下面的代码片段包含了检查Google Play服务所需要的代码:
public
class
MainActivity
extends
FragmentActivity {
...
//
Global constants
/*
* Define a request code to send to Google Play services
* This code is returned in Activity.onActivityResult
*/
private
final
static
int
CONNECTION_FAILURE_RESOLUTION_REQUEST
= 9000
;
...
//
Define a DialogFragment that displays the error dialog
public
static
class
ErrorDialogFragment
extends
DialogFragment {
//
Global field to contain the error dialog
private
Dialog mDialog;
//
Default constructor. Sets the dialog field to null
public
ErrorDialogFragment() {
super
();
mDialog
=
null
;
}
//
Set the dialog to display
public
void
setDialog(Dialog dialog) {
mDialog
=
dialog;
}
//
Return a Dialog to the DialogFragment.
@Override
public
Dialog onCreateDialog(Bundle savedInstanceState) {
return
mDialog;
}
}
...
/*
* Handle results returned to the FragmentActivity
* by Google Play services
*/
@Override
protected
void
onActivityResult(
int
requestCode,
int
resultCode, Intent data) {
//
Decide what to do based on the original request code
switch
(requestCode) {
...
case
CONNECTION_FAILURE_RESOLUTION_REQUEST :
/*
* If the result code is Activity.RESULT_OK, try
* to connect again
*/
switch
(resultCode) {
case
Activity.RESULT_OK :
/*
* Try the request again
*/
...
break
;
}
...
}
}
...
private
boolean
servicesConnected() {
//
Check that Google Play services is available
int
resultCode =
GooglePlayServicesUtil.
isGooglePlayServicesAvailable(
this
);
//
If Google Play services is available
if
(ConnectionResult.SUCCESS ==
resultCode) {
//
In debug mode, log the status
Log.d("Location Updates"
,
"Google Play services is available."
);
//
Continue
return
true
;
//
Google Play services was not available for some reason
}
else
{
//
Get the error code
int
errorCode =
connectionResult.getErrorCode();
//
Get the error dialog from Google Play services
Dialog errorDialog =
GooglePlayServicesUtil.getErrorDialog(
errorCode,
this
,
CONNECTION_FAILURE_RESOLUTION_REQUEST);
//
If Google Play services can provide an error dialog
if
(errorDialog !=
null
) {
//
Create a new DialogFragment for the error dialog
ErrorDialogFragment errorFragment =
new
ErrorDialogFragment();
//
Set the dialog in the DialogFragment
errorFragment.setDialog(errorDialog);
//
Show the error dialog in the DialogFragment
errorFragment.show(getSupportFragmentManager(),
"Location Updates"
);
}
}
}
...
}
在后续章节的代码片段中,都会调用这一方法来验证是否可获取Google Play服务。
三). 定义位置服务回调函数
要获取当前的地点,创建一个地点客户端,将它连接至定位服务,之后调用它的 getLastLocation() 方法。返回的值是最佳最新的地理位置,它基于你应用所请求的权限以及当前设备上已激活的定位传感器。
在你创建定位客户端之前,实现定位服务的接口,以和你的应用进行交互:
指定当定位连接上或者没有连接上时,定位服务调用的方法。
指定当尝试连接到定位客户端时,如果出现了错误,定位服务调用的方法。这一方法使用之前定义的 showErrorDialog 方法来显示一个错误对话框,它尝试使用Google Play服务来解决这一问题。
下面的样例代码展示了如何指定接口和定义相关的函数:
public
class
MainActivity
extends
FragmentActivity
implements
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener {
...
/*
* Called by Location Services when the request to connect the
* client finishes successfully. At this point, you can
* request the current location or start periodic updates
*/
@Override
public
void
onConnected(Bundle dataBundle) {
//
Display the connection status
Toast.makeText(
this
, "Connected"
, Toast.LENGTH_SHORT).show();
}
...
/*
* Called by Location Services if the connection to the
* location client drops because of an error.
*/
@Override
public
void
onDisconnected() {
//
Display the connection status
Toast.makeText(
this
, "Disconnected. Please re-connect."
,
Toast.LENGTH_SHORT).show();
}
...
/*
* Called by Location Services if the attempt to
* Location Services fails.
*/
@Override
public
void
onConnectionFailed(ConnectionResult connectionResult) {
/*
* Google Play services can resolve some errors it detects.
* If the error has a resolution, try sending an Intent to
* start a Google Play services activity that can resolve
* error.
*/
if
(connectionResult.hasResolution()) {
try
{
//
Start an Activity that tries to resolve the error
connectionResult.startResolutionForResult(
this
,
CONNECTION_FAILURE_RESOLUTION_REQUEST);
/*
* Thrown if Google Play services canceled the original
* PendingIntent
*/
}
catch
(IntentSender.SendIntentException e) {
//
Log the error
e.printStackTrace();
}
}
else
{
/*
* If no resolution is available, display a dialog to the
* user with the error.
*/
showErrorDialog(connectionResult.getErrorCode());
}
}
...
}
四). 连接定位客户端
现在回调函数已经就位了,创建定位客户端并且连接它至定位服务。
你应该在 onCreate() 方法中创建定位客户端,之后再 onStart() 方法中进行连接。这样定位服务就能在你的应用完全可见时维护当前的定位信息。在 onStop() 方法中关闭连接,这样当应用不可见时,定位服务就会停止更新地点。这样的连接方式还能节省电量。
Note:
只有在定位客户端连接到了定位服务后,当前的地点才能维护。假设没有其他应用连接到定位服务,如果你关闭了客户端,过一段时间后,调用了 getLastLocation() ,获得的结果可能将是过期的。
例如:
public
class
MainActivity
extends
FragmentActivity
implements
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener {
...
@Override
protected
void
onCreate(Bundle savedInstanceState) {
...
/*
* Create a new location client, using the enclosing class to
* handle callbacks.
*/
mLocationClient
=
new
LocationClient(
this
,
this
,
this
);
...
}
...
/*
* Called when the Activity becomes visible.
*/
@Override
protected
void
onStart() {
super
.onStart();
//
Connect the client.
mLocationClient.connect();
}
...
/*
* Called when the Activity is no longer visible.
*/
@Override
protected
void
onStop() {
//
Disconnecting the client invalidates it.
mLocationClient.disconnect();
super
.onStop();
}
...
}
五). 获取当前地点
要获取当前地点,调用 getLastLocation() ,例如:
public
class
MainActivity
extends
FragmentActivity
implements
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener {
...
//
Global variable to hold the current location
Location mCurrentLocation;
...
mCurrentLocation
=
mLocationClient.getLastLocation();
...
}
在下一节课中,将会向你展示从定位服务定期地接受地点更新的方法。

