Android LBS系列05 位置策略(一)
Location Strategies
定位的实现
在Android系统上实现定位主要是通过GPS或者是基于网络的定位方法。
GPS是精度最高的,但是它只在户外有用,并且很耗电,并且首次定位花费时间较长。
基于网络的定位利用通信网络蜂窝基站和Wi-Fi信号,这种定位方式在室内室外都能用,响应时间较短,耗电较少,但是精度较差。
为了在应用中获得用户的信息,你的location provider可以是GPS或者基于网络,也可以两者都用。
决定用户位置面临的挑战
从手机上获取用户的位置是个比较复杂的问题,无论采取的数据源是什么,总是有一些因素会导致位置信息包含误差,从而不准确。
误差来源如下:
多种位置信息源
GPS, Cell-ID, 和Wi-Fi都能为用户位置提供一定的线索。决定信任和采用哪些数据是一个需要权衡的过程,权衡时要考虑精度、速度、电池效率等。
用户移动
因为用户的位置会改变,所以应该考虑每隔一段时间重新估计用户位置。
变化的精度
每一个位置信息源的精度不是恒定的。也就是说位置估计即便是同一个信息源提供的,它的精确度也是不断在变化的。
请求位置更新
在Android中获取位置主要是通过回调函数。
首先通过 LocationManager
的 requestLocationUpdates()
方法注册监听器,向其中传入一个实现了 LocationListener
接口的对象。
你的 LocationListener
对象中必须实现一些回调函数,当用户位置改变或者当服务状态改变时,Location Manager就会调用这些回调函数。
比如,下面的代码就展示了如何定义一个 LocationListener
然后请求位置更新:
// Acquire a reference to the system Location Manager LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);// Define a listener that responds to location updates LocationListener locationListener = new LocationListener() {public void onLocationChanged(Location location) {// Called when a new location is found by the network location provider. makeUseOfNewLocation(location);}public void onStatusChanged(String provider, int status, Bundle extras) {}public void onProviderEnabled(String provider) {}public void onProviderDisabled(String provider) {}};// Register the listener with the Location Manager to receive location updates locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
requestLocationUpdates()
中的第一个参数指明了location provider的类型,第二个参数是通知的最小时间间隔,第三个参数是通知的最小的改变距离。
如果第二个和第三个参数都设置成0就表示要尽可能频繁地请求位置通知。
最后一个参数是用户自己定义的实现了LocationListener接口的对象,它接收位置更新的回调。
如果想要同时利用GPS和网络定位,可以调用 requestLocationUpdates()
两次,第一个参数分别是 GPS_PROVIDER
和 NETWORK_PROVIDER
。
权限设置
如果没有权限设置,程序在请求位置更新时将会失败。
<manifest ... ><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />... </manifest>
如果用NETWROK_PROVIDER, 那么需要声明 ACCESS_COARSE_LOCATION和INTERNET;
如果用GPS_PROVIDER, 那么需要声明 ACCESS_FINE_LOCATION;
ACCESS_FINE_LOCATION是包含了ACCESS_COARSE_LOCATION的,所以两者都用时可以只声明ACCESS_FINE_LOCATION。
建立一个最佳性能的模型
为了克服获取用户位置时的种种困难,定义一个模型,具体化你的应用如何取得用户位置。
这个模型包含了你何时开始和何时终止位置更新的监听,也包含了什么时候使用缓存的位置数据。
获取用户位置的流程
获取用户位置的典型流程如下:
1.首先开始应用。
2.在某一个点,开始监听位置更新。
3.维持一个当前位置的“最佳估计”。
4.停止对位置更新的监听。
5.利用最后一次的最佳位置估计。
这个模型是一个窗口,窗口从开始监听开始,从停止监听结束。
决定何时开始监听更新
可以从应用一开始就启动监听,也可以在用户触发某个特性后开始。
要清楚如果长时间监听位置会消耗很多电量,但是短时间的监听可能达不到足够的精度。
调用requestLocationUpdates()
开始监听:
LocationProvider locationProvider = LocationManager.NETWORK_PROVIDER; // Or, use GPS location data: // LocationProvider locationProvider = LocationManager.GPS_PROVIDER; locationManager.requestLocationUpdates(locationProvider, 0, 0, locationListener);
用上次定位的结果获取快速定位
初次获得位置信息可能会花费较长时间。在获得一个比较精确的定位之前,可以利用一个缓存的位置:调用getLastKnownLocation(String)
方法实现。
LocationProvider locationProvider = LocationManager.NETWORK_PROVIDER; // Or use LocationManager.GPS_PROVIDER Location lastKnownLocation = locationManager.getLastKnownLocation(locationProvider);
决定何时停止监听
位置获取和位置使用之间的时间间隔越小,对估计精度的改善越有利。
永远记住长时间的监听位置更新将会非常费电,所以一旦你得到你需要的信息,就应该停止监听位置更新,调用removeUpdates(PendingIntent)
方法实现:
// Remove the listener you previously added locationManager.removeUpdates(locationListener);
维护一个当前最佳估计
因为定位精度是实时变化的,所以很可能最新的位置并不是最准确的。
你应该制定一些标准并包含一套逻辑判断,来选择出最佳估计。
这套标准也是随着使用情景而变化的。
下面是你验证一个location fix的精确度时可以采取的步骤:
1.检查是否当期位置数据比之前的估计数据要新很多;
2.检查当前数据和之前数据的精度,谁更好;
3.检查当前数据是从哪个provider处获得的,然后决定是否更加信任它;
一个例子如下:
private static final int TWO_MINUTES = 1000 * 60 * 2;/** Determines whether one Location reading is better than the current Location fix* @param location The new Location that you want to evaluate* @param currentBestLocation The current Location fix, to which you want to compare the new one*/ protected boolean isBetterLocation(Location location, Location currentBestLocation) {if (currentBestLocation == null) {// A new location is always better than no locationreturn true;}// Check whether the new location fix is newer or olderlong timeDelta = location.getTime() - currentBestLocation.getTime();boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;boolean isNewer = timeDelta > 0;// If it's been more than two minutes since the current location, use the new location// because the user has likely movedif (isSignificantlyNewer) {return true;// If the new location is more than two minutes older, it must be worse } else if (isSignificantlyOlder) {return false;}// Check whether the new location fix is more or less accurateint accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());boolean isLessAccurate = accuracyDelta > 0;boolean isMoreAccurate = accuracyDelta < 0;boolean isSignificantlyLessAccurate = accuracyDelta > 200;// Check if the old and new location are from the same providerboolean isFromSameProvider = isSameProvider(location.getProvider(),currentBestLocation.getProvider());// Determine location quality using a combination of timeliness and accuracyif (isMoreAccurate) {return true;} else if (isNewer && !isLessAccurate) {return true;} else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {return true;}return false; }/** Checks whether two providers are the same */ private boolean isSameProvider(String provider1, String provider2) {if (provider1 == null) {return provider2 == null;}return provider1.equals(provider2); }
调整模型以节约电量和进行数据交换
当你测试模型的时候,可能发现你的模型需要做一些调整,以平衡它的准确度和性能。下面是一些你可以改变的地方:
减小流程的窗口尺寸
窗口尺寸减小,意味着与GPS和网络的交互减少,这样就可以节约电量。但是这样也就减少了获得最佳位置估计可以利用的位置数。
降低location provider返回更新的频率
在窗口中降低更新频率也可以改善电池效率,但是会导致精度的丢失。requestLocationUpdates()
通过其中两个参数就可以设定更新的时间和空间间隔,从而设定频率。
限制provider
根据应用的特定环境或者目标精度等级,可以选择只利用基于网络的定位或者只利用GPS定位,而不是同时利用两者。只与其中的一者交互将减少电量使用,但是会有潜在的精度丢失。
参考资料:
API Guides:Location Strategies
http://developer.android.com/guide/topics/location/strategies.html
转载于:https://www.cnblogs.com/mengdd/archive/2013/01/12/2857859.html
Android LBS系列05 位置策略(一)相关推荐
- Android 系统(243)---Android进程系列第一篇---进程基础
Android进程系列第一篇---进程基础 内容预览.png 概述: 本文主要讲解进程基础,更深入的认识有血有肉的进程,内容涉及进程控制块,信号,进程FD泄露等等.仅供参考,欢迎指正. 一.从Linu ...
- Android学习系列(10)--App列表之拖拽ListView(上)
研究了很久的拖拽ListView的实现,受益良多,特此与尔共飨. 鉴于这部分内容网上的资料少而简陋,而具体的实现过程或许对大家才有帮助,为了详尽而不失真,我们一步一步分析,分成两篇文章. ...
- Android Studio系列教程三:快捷键
原文出处:http://stormzhang.com/devtools/2014/12/09/android-studio-tutorial3/ Android Studio 1.0正式版发布啦 今天 ...
- Android Studio系列(二)使用Android Studio开发/调试整个android系统源代码(不定时更新)
本文是以源码中development/tools/idegen/README作为指导文档,给出了使用Android Studio导入Android源码的方法步骤. 环境: Ubuntu 12.04,o ...
- Android系统启动系列----init进程
Android系统启动系列 Android系统启动系列----init进程 Android系统启动系列----Zygote进程 引言 在开发app的过程中,是不是会有疑问: java程序的运行不是从m ...
- [转]Android Studio系列教程六--Gradle多渠道打包
转自:http://www.stormzhang.com/devtools/2015/01/15/android-studio-tutorial6/ Android Studio系列教程六--Grad ...
- Android学习系列(15)--App列表之游标ListView(索引ListView)
游标ListView,提供索引标签,使用户能够快速定位列表项. 也可以叫索引ListView,有的人称也为Tweaked ListView,可能更形象些吧. 一看图啥都懂了: ...
- Android自定义控件系列--Path综述
Android自定义控件系列–Path综述 项目源码 点击查看详情 Path 中文 释义为路径 然而它在自定义控件中却有着神一样的着色,这个神,是创造神奇效果的意思 1 Path 的创建 Path p ...
- Android学习系列(11)--App列表之拖拽ListView(下)
接着上篇Android学习系列(10)--App列表之拖拽ListView(上)我们继续实现ListView的拖拽效果. 7.重写onTouchEvent()方法. 在这个方法中我们主要是处 ...
最新文章
- 排序算法 JavaScript
- [转] 2016前端开发技术巡礼
- 百度智能小程序正式开源,开发方案详解
- 【项目总结】之——导出Excel
- 柯南变声器的算法实现原理
- centos 编译 mysql_centos 编译安装mysql
- php破坏代码,php不破坏单词截取子字符串
- Android VideoView无法播放网络视频
- matlab音频信号的采样与重构,信号与系统实验(MATLAB 西电版)实验21 综合实验2-音频信号的采样与重构.ppt...
- Linux 设备树知识点
- DBGrid 应用全书
- java(6) ArrayList源码
- 2021年安全员-A证(江西省)报名考试及安全员-A证(江西省)考试平台
- 人人商城开启整点秒杀功能
- mac下keytool 错误: java.lang.Exception: 密钥库文件不存在
- 简述计算机视觉在各领域中的成功应用,计算机视觉技术在茶叶领域中的应用现状及展望...
- 伊利诺伊大学厄本那 香槟分校计算机科学,伊利诺伊大学厄本那-香槟分校计算机科学面试经验汇总...
- php图片生成邀请函,科学网—如何制作邀请函 - 樊晓英的博文
- 【肖四出了】考研政治肖秀荣预测四套卷已出!
- Excel如何快速填写二维表
热门文章
- java 二进制 归属权限_【Java EE 学习 75 上】【数据采集系统第七天】【二进制运算实现权限管理】【权限分析和设计】...
- 外呼机器人起名_智能外呼机器人,目前都有哪些公司做产品?
- 靶场练习第一天~vulnhub靶场之Me-and-My-Girlfriend-1
- Win32ASM学习[20]:子程序
- Scala中的while循环
- 02-图像的几何变换
- 面向对象 抽象(abstract)
- 线性表----链式表
- app调html页面,app界面管理(风格色调).html
- c++中的deque容器