注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好。

原文链接:http://developer.android.com/training/location/receive-location-updates.html


如果你的应用有导航的功能,你可能会希望可以定期获取用户的地理位置。虽然你可以通过LocationClient.getLastLocation()做到这一点,但是一个更加直接的方法是向定位服务申请定期更新。作为响应,定位服务会自动用最佳的地理位置信息(基于当前激活的可以提供位置信息的传感器,如WiFi或者GPS)更新到你的应用。

要从定位服务定期获取地理位置更新,你使用定位客户端发送一个请求。根据请求的形式,定位服务或是激活一个回调函数,并把一个Location对象传递给该函数,或是发送一个Intent,在其数据部分包含了地理位置信息。有两方面因素会影响精度和频率,一个是你的应用申请的定位权限,一个是你在请求中传递给定位服务的参数。


一). 指定应用权限

使用位置服务的应用必须请求定位权限。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()方法。

Note:

要使你的应用可以兼容1.6及以后版本的系统,显示DialogFragment的activity必须是FragmentActivity的子类,而非Activity。使用FragmentActivity还可以允许你调用getSupportFragmentManager()方法来显示DialogFragment。

由于你一直需要在你的代码多个地方检查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 intCONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;...// Define a DialogFragment that displays the error dialogpublic static class ErrorDialogFragment extends DialogFragment {// Global field to contain the error dialogprivate Dialog mDialog;// Default constructor. Sets the dialog field to nullpublic ErrorDialogFragment() {super();mDialog = null;}// Set the dialog to displaypublic void setDialog(Dialog dialog) {mDialog = dialog;}// Return a Dialog to the DialogFragment.
        @Overridepublic Dialog onCreateDialog(Bundle savedInstanceState) {return mDialog;}}.../** Handle results returned to the FragmentActivity* by Google Play services*/@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {// Decide what to do based on the original request codeswitch (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 availableint resultCode =GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);// If Google Play services is availableif (ConnectionResult.SUCCESS == resultCode) {// In debug mode, log the statusLog.d("Location Updates","Google Play services is available.");// Continuereturn true;// Google Play services was not available for some reason} else {// Get the error codeint errorCode = connectionResult.getErrorCode();// Get the error dialog from Google Play servicesDialog errorDialog = GooglePlayServicesUtil.getErrorDialog(errorCode,this,CONNECTION_FAILURE_RESOLUTION_REQUEST);// If Google Play services can provide an error dialogif (errorDialog != null) {// Create a new DialogFragment for the error dialogErrorDialogFragment 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服务。


三). 定义位置服务回调函数

在你创建定位客户端之前,实现定位服务的接口,以和你的应用进行交互:

ConnectionCallbacks

指定当定位连接上或者没有连接上时,定位服务调用的方法。

OnConnectionFailedListener

指定当尝试连接到定位客户端时,如果出现了错误,定位服务调用的方法。这一方法使用之前定义的showErrorDialog方法来显示一个错误对话框,它尝试使用Google Play服务来解决这一问题。

下面的样例代码展示了如何指定接口和定义相关的函数:

public class MainActivity extends FragmentActivity implementsGooglePlayServicesClient.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*/@Overridepublic void onConnected(Bundle dataBundle) {// Display the connection statusToast.makeText(this, "Connected", Toast.LENGTH_SHORT).show();}.../** Called by Location Services if the connection to the* location client drops because of an error.*/@Overridepublic void onDisconnected() {// Display the connection statusToast.makeText(this, "Disconnected. Please re-connect.",Toast.LENGTH_SHORT).show();}.../** Called by Location Services if the attempt to* Location Services fails.*/@Overridepublic 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());}}...
}

定义地理位置更新回调函数

定位服务或是以一个Intent的形式,或者以一个参数的形式将为之更新传递给一个你定义的回调函数。这节课将会讲解如何使用一个回调函数来获取更新,课程中使用的代码基本可以用于任何应用场景。如果你想要以一个Intent的形式接收位置更新,可以阅读:Recognizing the User's Current Activity。它提供了类似的可以参考的模板。

位置服务所调用的将为之更新发送给你的应用的回调函数是在LocationListener接口的onLocationChanged()方法中指定的。传入的参数是一个Location对象,包含了地点的经纬度。下面的代码片段展示了如何指定接口和定义方法:

public class MainActivity extends FragmentActivity implementsGooglePlayServicesClient.ConnectionCallbacks,GooglePlayServicesClient.OnConnectionFailedListener,LocationListener {...// Define the callback method that receives location updates
    @Overridepublic void onLocationChanged(Location location) {// Report to the UI that the location was updatedString msg = "Updated Location: " +Double.toString(location.getLatitude()) + "," +Double.toString(location.getLongitude());Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();}...
}

现在你已经有了回调函数,你可以配置位置更新的请求了。首先第一步是指定控制更新的参数。


四). 指定更新参数

定位服务允许你控制更新之间的时间间隔以及你期望的位置精确度,通过设置LocationRequest对象中的值,再将这一对象作为你的请求的一部分发出以开始更新。

首先,设置下列间隔参数:

更新间隔:

通过LocationRequest.setInterval()设置。这一方法以毫秒为单位设置你的应用接收更新的事件间隔。如果没有其它应用从定位服务接收更新,那么你的应用将会以这一频率接收更新。

最快更新间隔:

通过LocationRequest.setFastestInterval()设置。这一方法设置的是你的应用能处理更新的最快间隔时间,以毫秒为单位。你需要设置这个频率是因为其它应用也会影响位置更新非频率。定位服务会以所有应用通过LocationRequest.setInterval()设置的最快的间隔时间来发送更新。如果这一频率比你的应用能够处理的频率要快,那么你可能会遇到UI闪烁或数据溢出等问题。为了避免这一情况发生,应该调用LocationRequest.setFastestInterval()这一方法设置更新频率的最高限额。

调用LocationRequest.setFastestInterval()方法还可以节省电量。当你通过LocationRequest.setInterval()请求了一个更新间隔后,又用LocationRequest.setFastestInterval()请求了一个最大速率后,你的应用会以正常速率进行更新。如果其它应用使用了一个更快的更新速率,那么你的更新频率也会加快。如果没有其它应用申请了更快的更新速率,那么你的应用会以LocationRequest.setInterval()中所设置的速率进行更新。

接下来,设置精度参数。在一个前台应用程序中,你需要以高频率更新地理位置,所以使用LocationRequest.PRIORITY_HIGH_ACCURACY设置精度。

下面的代码片段展示课如何设置更新间隔和精度:

public class MainActivity extends FragmentActivity implementsGooglePlayServicesClient.ConnectionCallbacks,GooglePlayServicesClient.OnConnectionFailedListener,LocationListener {...// Global constants
    ...// Milliseconds per secondprivate static final int MILLISECONDS_PER_SECOND = 1000;// Update frequency in secondspublic static final int UPDATE_INTERVAL_IN_SECONDS = 5;// Update frequency in millisecondsprivate static final long UPDATE_INTERVAL =MILLISECONDS_PER_SECOND * UPDATE_INTERVAL_IN_SECONDS;// The fastest update frequency, in secondsprivate static final int FASTEST_INTERVAL_IN_SECONDS = 1;// A fast frequency ceiling in millisecondsprivate static final long FASTEST_INTERVAL =MILLISECONDS_PER_SECOND * FASTEST_INTERVAL_IN_SECONDS;...// Define an object that holds accuracy and frequency parameters
    LocationRequest mLocationRequest;...@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// Create the LocationRequest objectmLocationRequest = LocationRequest.create();// Use high accuracy
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);// Set the update interval to 5 seconds
        mLocationRequest.setInterval(UPDATE_INTERVAL);// Set the fastest update interval to 1 second
        mLocationRequest.setFastestInterval(FASTEST_INTERVAL);...}...
}

Note:

如果你的应用要访问网络或者在接收到更新后需要做其它长期的任务,那么应该调整更新频率到一个比较慢的值。这可以避免你的应用接收到太多它来不及处理的更新数据。一旦长期处理的任务结束了,可以再通过设置最快更新频率到一个较快的值。


五). 开始位置更新

要发送位置更新请求,在onCreate()创建一个定位客户端,之后连接它,并通过requestLocationUpdates()发起请求。因为你的客户端必须连接以后你的应用才能收到更新,所以你应该在onStart()方法中连接到客户端。这能保证当你的应用可见时,你都能获取一个已连接的有效的客户端。因为你需要在发出请求前先进行连接,所以在ConnectionCallbacks.onConnected()发出更新请求。

另外要记住用户可能会有各种各样的原因希望关闭位置更新。你应该为用户提供一个这样做的方法,并且你应该保证当更新关闭了之后,你不会在onStart()中启动更新。为了记录用户的设置,在onPause()方法中保存应用的SharedPreferences,并在onResume()方法中获取它。

下面的代码片段展示了如何在onCreate()方法中设置客户端,以及如何在onStart()方法中连接并发出更新请求:

public class MainActivity extends FragmentActivity implementsGooglePlayServicesClient.ConnectionCallbacks,GooglePlayServicesClient.OnConnectionFailedListener,LocationListener {...// Global variables
    ...LocationClient mLocationClient;boolean mUpdatesRequested;...@Overrideprotected void onCreate(Bundle savedInstanceState) {...// Open the shared preferencesmPrefs = getSharedPreferences("SharedPreferences",Context.MODE_PRIVATE);// Get a SharedPreferences editormEditor = mPrefs.edit();/** Create a new location client, using the enclosing class to* handle callbacks.*/mLocationClient = new LocationClient(this, this, this);// Start with updates turned offmUpdatesRequested = false;...}...@Overrideprotected void onPause() {// Save the current setting for updatesmEditor.putBoolean("KEY_UPDATES_ON", mUpdatesRequested);mEditor.commit();super.onPause();}...@Overrideprotected void onStart() {...mLocationClient.connect();}...@Overrideprotected void onResume() {/** Get any previous setting for location updates* Gets "false" if an error occurs*/if (mPrefs.contains("KEY_UPDATES_ON")) {mUpdatesRequested =mPrefs.getBoolean("KEY_UPDATES_ON", false);// Otherwise, turn off location updates} else {mEditor.putBoolean("KEY_UPDATES_ON", false);mEditor.commit();}}.../** 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*/@Overridepublic void onConnected(Bundle dataBundle) {// Display the connection statusToast.makeText(this, "Connected", Toast.LENGTH_SHORT).show();// If already requested, start periodic updatesif (mUpdatesRequested) {mLocationClient.requestLocationUpdates(mLocationRequest, this);}}...
}

更多关于保存配置信息的知识,可以查看:Saving Key-Value Sets。


六). 停止位置更新

要停止位置更新,在onPause()方法中保存更新标识的状态,并在onStop()方法中通过调用removeLocationUpdates(LocationListener)来停止更新,例如:

public class MainActivity extends FragmentActivity implementsGooglePlayServicesClient.ConnectionCallbacks,GooglePlayServicesClient.OnConnectionFailedListener,LocationListener {.../** Called when the Activity is no longer visible at all.* Stop updates and disconnect.*/@Overrideprotected void onStop() {// If the client is connectedif (mLocationClient.isConnected()) {/** Remove location updates for a listener.* The current Activity is the listener, so* the argument is "this".*/removeLocationUpdates(this);}/** After disconnect() is called, the client is* considered "dead".*/mLocationClient.disconnect();super.onStop();}...
}

现在你已经有了请求并接收定期位置更新的基本应用框架。你可以将这节课中所讲的东西结合到导航,行为识别,反地址解析等等场景中。

下一节课中,我们将会讲解如何使用当前地点显示现在的街道地址。

转载于:https://www.cnblogs.com/jdneo/p/3714124.html

【Android Developers Training】 104. 接受地点更新相关推荐

  1. 【Android Developers Training】 6. 配置Action Bar

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  2. 【Android Developers Training】 81. 解析XML数据

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  3. 【Android Developers Training】 58. 缓存位图

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  4. 【Android Developers Training】 75. 使用NSD

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  5. 【Android Developers Training】 93. 创建一个空验证器

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  6. 【Android Developers Training】 68. 序言:添加动画

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  7. 【Android Developers Training】 0. 序言:构建你的第一个应用

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  8. 【Android Developers Training】 8. 定义Action Bar风格

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  9. 【Android Developers Training】 20. 创建一个Fragment

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

最新文章

  1. c++11 之模板定义别名(using)
  2. C# 垃圾回收机制(转)
  3. Oracle中,如何查看FRA(Flashback Recovery Area)的利用率
  4. Java后端返回通用接口设计
  5. 23种设计模式之解释器模式
  6. cisco switch configuration
  7. 从前序与中序遍历序列构造二叉树Python解法
  8. cesh222/h2这到底是一个什么鬼cesces
  9. 工作总结10:解决vuex刷新数据消失
  10. DWZ中navTab使用解析
  11. pycharm引用python_在Python/Pycharm中找不到引用“xxx”
  12. 使用ML.Net和C#进行机器学习
  13. c# 判断是否存在次盘符_C# 怎么自动识别U盘盘符 进行判断 读写操作
  14. linux java 自动安装_Centos7 linux 卸载自带安装的jdk 并yum自动安装jdk1.8
  15. 尝试重新启动计算机和应用程序 错误38,win10系统运行coreldraw x7 38错误怎么办?win10 cdr 错误38解决方法...
  16. CSS背景图片background如何改变大小以及样式设置
  17. Debian 安装手记
  18. supervisor查询状态报错
  19. android 仿微信群聊头像 合成图片
  20. background系列属性(background-color背景颜色、background-image背景图片、background-repeat重复方式以及background-position)

热门文章

  1. sdut 2107 DFS
  2. C语言从文件中读入矩阵,并且将矩阵转置
  3. 【解决方案】调用multiprocessing中创建的文件无法打开的问题FileNotFoundError: [WinError 2]
  4. C++:顺序表的基本操作(待完善)
  5. 转载文章,感觉真的很心酸
  6. linux系统管理常用命令
  7. 【MySQL经典案例分析】 Waiting for table metadata lock
  8. struts-2.5.14.1 中web.xml的基本配置
  9. Linux chmod命令详解
  10. JavaScript采用append添加的元素错误