在 Android 上获取用户当前位置的最简单、最可靠的方法是什么?
对于只需要偶尔粗略估计用户位置的应用程序来说,Android 上的 LocationManager
API 似乎使用起来有点麻烦。
我正在开发的应用程序本身并不是真正的位置应用程序,但它确实需要获取用户的位置才能显示附近企业的列表。它不需要担心用户是否正在走动或类似的事情。
这就是我想做的:
- 向用户显示附近位置的列表。
- 预加载用户的位置,以便当我在
Activity
X 中需要它时,它就可用。 - 我并不特别关心更新的准确性或频率。只要抓住一个位置就足够了,只要它不是太远。也许如果我想变得更花哨,我会每隔几分钟左右更新一次位置,但这不是一个重要的优先事项。
- 适用于任何具有 GPS 或网络位置提供商的设备。
看起来应该没那么难,但在我看来,我必须启动两个不同的位置提供程序(GPS 和网络)并管理每个提供程序的生命周期。不仅如此,我还必须在多个活动中复制相同的代码才能满足#2。我过去曾尝试使用 getBestProvider() 来将解决方案简化为仅使用一个位置提供程序,但这似乎只能为您提供最好的“理论”提供程序,而不是实际提供的提供程序给您最好的结果。
有没有更简单的方法来实现这一点?
The LocationManager
API on Android seems like it's a bit of a pain to use for an application that only needs an occasional and rough approximation of the user's location.
The app I'm working on isn't really a location app per se, but it does need to get the user's location in order to display a list of nearby businesses. It doesn't need to worry about if the user is moving around or anything like that.
Here's what I'd like to do:
- Show the user a list of nearby locations.
- Preload the user's location so that by the time I need it in
Activity
X, it will be available. - I don't particularly care about accuracy or frequency of update. Just grabbing one location is sufficient as long as it's not way off. Maybe if I want to be fancy I'll update the location once every few mins or so, but it's not a huge priority.
- Work for any device as long as it has either a GPS or a Network Location provider.
It seems like it shouldn't be that hard, but it appears to me that I have to spin up two different location providers (GPS and NETWORK) and manage each's lifecycle. Not only that, but I have to duplicate the same code in multiple activities to satisfy #2. I've tried using getBestProvider()
in the past to cut the solution down to just using one location provider, but that seems to only give you the best "theoretical" provider rather than the provider that's actually going to give you the best results.
Is there a simpler way to accomplish this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(28)
这就是我所做的:
这是我使用我的类的方式:
这是 MyLocation 类:
有人可能还想修改我的逻辑。例如,如果您从网络提供商获得更新,请不要停止侦听器,而是继续等待。 GPS 提供了更准确的数据,因此值得等待。如果计时器到了并且您已从网络获得更新但未从 GPS 获得更新,则您可以使用网络提供的值。
另一种方法是使用 LocationClient http://developer.android.com/training/位置/retrieve-current.html。但它需要在用户设备上安装 Google Play Services apk。
Here's what I do:
Here's how I use my class:
And here's MyLocation class:
Somebody may also want to modify my logic. For example if you get update from Network provider don't stop listeners but continue waiting. GPS gives more accurate data so it's worth waiting for it. If timer elapses and you've got update from Network but not from GPS then you can use value provided from Network.
One more approach is to use LocationClient http://developer.android.com/training/location/retrieve-current.html. But it requires Google Play Services apk to be installed on user device.
在搜索如何获得最佳精确用户位置的最佳实现之后,我设法结合所有最佳方法并提出以下类:
如果启用了 GPS,该类将尝试连接到
min_gps_sat_count
卫星。否则返回LocationManager.getBestProvider()
位置。检查代码!After searching for best implementation how to get best precise user location I managed to combine all the best methods and come up with following class:
This class tries to connect to
min_gps_sat_count
satellites if GPS is enabled. Else returnsLocationManager.getBestProvider()
location. Check the code!使用 Fedor 的解决方案,我经历了回调
gotLocation
的多次执行。当gotLocation方法“足够长”时,这似乎是由于重写的
LocationListener.onLocationChanged
方法中的竞争条件造成的。我不确定,但我猜removeUpdates
会阻止新消息在 Looper 队列中排队,但它不会删除那些已经排队但尚未消耗的消息。因此出现了竞争条件。为了减少这种错误行为的可能性,可以在触发 onLocationChanged 事件之前调用removeUpdates,但我们仍然存在竞争条件。
我发现的最佳解决方案是将
requestLocationUpdates
替换为requestSingleUpdate
。这是我的版本,基于 Fedor 的解决方案,使用 Handler 向 Looper 线程发送消息:
我从自定义的 Looper 线程中使用此类,如下所示:
其中 Coords 是一个具有两个属性的简单类:纬度和经度。
With Fedor's solution I've experienced multiple execution of the callback
gotLocation
.It seems to be due to a race condition in the overridden
LocationListener.onLocationChanged
method, when gotLocation method is 'long enough'. I'm not sure, but I guessremoveUpdates
prevents the enqueueing of new messages in the Looper queue, but it doesn't remove those already enqueued but not yet consumed. Hence the race condition.To reduce the probability of this wrong behavior it's possible to call removeUpdates before firing the onLocationChanged event, but still we have the race condition.
The best solution I found is to replace
requestLocationUpdates
withrequestSingleUpdate
.This is my version, based on Fedor's solution, using an Handler to send a message to the looper thread:
I use this class from a customized looper thread, like the following one:
where Coordinates is a simple class with two properties: latitude and longitude.
我创建了一个小应用程序,其中包含逐步描述,以获取当前位置的 GPS 坐标。
以下 URL 中的完整示例源代码:
看看它是如何工作的:
我们需要做的就是在清单文件中添加此权限
并像这样创建 LocationManager 实例
检查GPS是否启用
然后实现LocationListener并获取坐标
这是要执行的示例代码
I have created small application with step by step description to gets current locations GPS co-ordinates.
Complete example source code in below URL:
See How it works :
All we need to do is add this permission in manifest file
and create LocationManager instance like this
Check GPS is enabled or not
then implement LocationListener and Get Coordinates
here is the sample code to do
您始终可以使用 LocationManager.getLastKnownLocation() 但就像它说的那样,它可能已经过时了。
获取大致位置的一个简单方法是注册网络(通常非常快)。
然后
在监听器的
onLocationChanged()
方法中执行操作。You could always just use LocationManager.getLastKnownLocation() but like it says it could be out of date.
And a simple way to get a general location could be registering for the network (usually pretty fast).
and then doing
in the
onLocationChanged()
method of the listener.我在 demonuts.com。您可以在这里找到更多说明,也可以下载整个演示源代码以便更好地理解。
那里已经有很多答案,但我想展示使用 Google API 获取位置的最新方法,因此新程序员可以使用新方法:
首先,将其放入 gradle 文件中,
然后实现必要的接口,
声明实例,
将其放入
onCreate 中()
最后,覆盖必要的方法
不要忘记在运行应用程序之前启动设备中的 GPS。
I have written detailed tutorial covering current location here on demonuts.com.You can find more description here and also you can download whole demo source code for better understanding.
There are already many answers there but I want to show latest way to get location using Google API, so new programmers can use new method:
First of all, put this in gradle file
then implement necessary interfaces
declare instances
put this in
onCreate()
At last, override necessary methods
Don't forget to start GPS in your device before running app.
实际上我们可以使用两个提供商(GPS 和网络)。他们只是共享一个公共侦听器:
这是必要的,因为
OnLocationChanged()
方法始终需要及时调用。Actualy we can use the two providers(GPS & NETWORK). And they just share a public listener:
This is necessary because the
OnLocationChanged()
method always need to be called in time.我不确定基于位置的服务是否可以从其他位置获取位置GPS 以外的基础设施,但根据那篇文章,这似乎确实是可能的:
I am not sure if the Location-Based Services can get the location from other infrastructures other than GPS, but according to that article, it does seem possible:
使用下面的代码,它将提供最好的可用提供商:
Use the below code, it will give the best provider available:
推荐的方法是使用
LocationClient
:首先,定义位置更新间隔值。根据您的需要进行调整。
让您的
Activity
实现GooglePlayServicesClient.ConnectionCallbacks
、GooglePlayServicesClient.OnConnectionFailedListener
和LocationListener
。然后,在
Activity
的onCreate()
方法中设置LocationClient
:将所需的方法添加到您的
Activity
>;onConnected()
是LocationClient
连接时调用的方法。onLocationChanged()
是您检索最新位置的位置。请务必连接/断开
LocationClient
,这样它只会在绝对必要时使用额外的电池,这样 GPS 就不会无限期地运行。必须连接LocationClient
才能从中获取数据。获取用户的位置。首先尝试使用
LocationClient
;如果失败,则返回到LocationManager
。The recommended way to do this is to use
LocationClient
:First, define location update interval values. Adjust this to your needs.
Have your
Activity
implementGooglePlayServicesClient.ConnectionCallbacks
,GooglePlayServicesClient.OnConnectionFailedListener
, andLocationListener
.Then, set up a
LocationClient
in theonCreate()
method of yourActivity
:Add the required methods to your
Activity
;onConnected()
is the method that is called when theLocationClient
connects.onLocationChanged()
is where you'll retrieve the most up-to-date location.Be sure to connect/disconnect the
LocationClient
so it's only using extra battery when absolutely necessary and so the GPS doesn't run indefinitely. TheLocationClient
must be connected in order to get data from it.Get the user's location. First try using the
LocationClient
; if that fails, fall back to theLocationManager
.尽管这里已经给出了答案。我只是想与全世界分享这一点,以防遇到这种情况。
我的要求是我需要最多在 30 到 35 秒内获取用户的当前位置,所以这是我按照 Nirav Ranpara 的答案做出的解决方案。
1.我创建了MyLocationManager.java类来处理所有GPS和网络内容
2.我创建了一个接口(回调)OnLocationDetectionListener .java 以便将结果传达回调用片段或活动
3. 然后我创建了一个实现
OnLocationDetectionListener<的 MainAppActivty.java Activity /code> 界面,这是我如何在其中接收我的位置
4. 将以下权限添加到您的清单文件中
希望这对其他人有帮助:)
Even though the answer is already given here. I just wanted to share this to the world incase the come across such scenario.
My requirement was that i needed to get a user's current location within 30 to 35 seconds at max so here is the solution i made following Nirav Ranpara's Answer.
1. I made MyLocationManager.java class which handles all the GPS and Network stuff
2. I made an Interface (callback) OnLocationDetectectionListener.java in order to communicate the results back to the calling fragment or activity
3. Then i made an MainAppActivty.java Activity that implements
OnLocationDetectectionListener
interface and here is how i receive my location in it4. Add the following permissions to your manifest file
Hope this is helpful to others :)
对@Fedor 解决方案的改进。
我们可以使用位置管理器的 requestSingleUpdate 方法,而不是请求具有“0”时间间隔和“0”距离的位置。更新的代码(kotlin 版本)
要获取位置只需调用 getLocation 方法 -
注意:
在调用 getLocation 方法之前,必须授予所需的位置权限。
Improvements to @Fedor's solution.
Rather than requesting location with '0' time interval and '0' distance, we can use the location manager's requestSingleUpdate method. Updated code(kotlin version)
To get location need to just call getLocation method as -
Note:
Before calling getLocation method, required location permission must be granted.
这就是我请求用户权限的方式。
在 AndroidManifest.xml 中的应用程序标记之外添加这些权限请求。
然后在 App Gradle 文件中添加 Google 的位置依赖项。
现在声明一些全局变量。
在您的 Activity 的 OnCreate 方法中(我无法正确格式化代码,对此表示歉意)
现在创建这两个函数。
第二种方法
Constant.kt 的
This is the way I am requesting User Permissions.
Outside your application tag in AndroidManifest.xml add these permission requests.
Then add Google's Location dependencies in the App Gradle file.
Now declare some Global variables.
In OnCreate method of your Activity (I was not able to Format the Code Properly, Apology for that)
Now create both the functions.
Second Method
For Constant.kt
从过去一年多开始,我一直使用 GPS_PROVIDER 和 NETWORK_PROVIDER 的组合来获取当前位置,并且运行良好,但从过去几个月开始,我在长时间延迟后获取位置,所以我切换到最新的 API FusedLocationProviderClient 和它工作得很好。
这是我编写的用于使用 FusedLocationProviderClient 获取当前位置的类。
在下面的代码中,我使用了一个计时器来等待一段时间以获取当前位置,我将计时器设置为15秒延迟,您可以根据自己的情况进行更改。
并从活动中调用它,下面是代码
在 AndroidManifest.xml 中添加以下条目
From last more than one year, I was using the combination of GPS_PROVIDER and NETWORK_PROVIDER to get the current location and it was working good, but from last few months I'm getting location after a long delay, so I switched to latest API FusedLocationProviderClient and it is working pretty good.
Here is the class which I wrote to get current location by using FusedLocationProviderClient.
In below code, I used a timer to wait for while to get the current location, I scheduled timer 15 seconds delay, you can change it according to you.
And called this from activity, here is the code
Add following entries in the AndroidManifest.xml
要获取并显示用户的当前位置,您还可以使用
MyLocationOverlay
。假设您的 Activity 中有一个mapView
字段。要显示用户位置,您需要执行的操作如下:这会从 GPS 或网络获取当前位置。如果两者都失败,
enableMyLocation()
将返回false
。至于该区域周围事物的位置,
ItemizedOverlay
应该可以解决问题。我希望我没有误解你的问题。祝你好运。
To get and show the user's current location, you could also use
MyLocationOverlay
. Suppose you have amapView
field in your activity. All you would need to do to show the user location is the following:This gets the current location from either the GPS or the network. If both fail,
enableMyLocation()
will returnfalse
.As for the locations of things around the area, an
ItemizedOverlay
should do the trick.I hope I haven't misunderstood your question. Good luck.
这是提供用户当前位置的代码
创建地图活动:
main.xml:
并在清单中定义以下权限:
This is the code that provides user current location
create Maps Activty:
main.xml:
and define following permission in manifest:
编辑:使用 Google Play 服务库(2014 年 7 月)中的最新位置服务 API 进行了更新
我建议您使用新的 位置服务 API,可从 Google Play 服务库获取,该库提供了更强大的高级框架,可自动执行位置提供商选择和电源管理等任务。根据官方文档:“... Location API 让您可以轻松构建位置感知应用程序,而无需关注底层定位技术的细节。它们还可以让您通过使用所有功能来最大限度地降低功耗设备硬件。”
有关更多信息,请访问:让您的应用感知位置
查看完整示例使用最新的位置服务 API 访问:Android LocationClient类已弃用,但在文档中使用
EDIT: Updated with the latest Location Service API from Google Play Services library (July 2014)
I would recommend you to use the new Location Service API, available from the Google Play Services library, which provides a more powerful, high-level framework that automates tasks such as location provider choice and power management. According to the official documentation: "... Location API make it easy for you to build location-aware applications, without needing to focus on the details of the underlying location technology. They also let you minimize power consumption by using all of the capabilities of the device hardware."
For further information visit: Making Your App Location-Aware
To see a full example using the latest Location Service API visit: Android LocationClient class is deprecated but used in documentation
它需要很多东西才能在 Android 中获取位置更新,
需要大量样板代码。
您需要注意
如果在我创建的 Android-EasyLocation(小型 Android 库) 它将处理所有这些事情,您可以专注于业务逻辑。
您所需要的只是扩展 EasyLocationActivity 以及此
或
Checkout 示例应用程序以及此处所需的步骤 https://github.com/akhgupta/Android-EasyLocation
It requires lots of things in place to get location updates in android,
requires lots of bolierplate code.
You need to take care of
I have created Android-EasyLocation (small android library) which will take care all this stuff and you can focus on business logic.
All you need is extend EasyLocationActivity and this
or
Checkout sample app and steps needed here at https://github.com/akhgupta/Android-EasyLocation
@Fedor Greate 答案的 Kotlin 版本:
类的用法:
MyLocation
类:Kotlin version of @Fedor Greate answer:
usage of class:
MyLocation
Class :简单且最佳的地理位置定位方法。
Simple and best way for GeoLocation.
这里有点晚了,但在这种情况下我会使用 Google 地图 API 并使用谷歌地图的纬度和经度 API 标记附近的位置。另外,如果您可以在地图上显示他/她的位置,那么用户体验会更好。无需担心用户位置的更新或使用 android api 进行搜查。让谷歌地图为您处理内部事务。
@emmby 可能已经在他的应用程序中解决了这个问题,但为了将来的参考,我建议其他开发人员查看 Google 地图 API 以获取特定于位置的内容。
编辑:用于显示 用户位置的链接谷歌地图
A bit late here but what I would in such a situation is to use Google Maps API and mark the nearby locations using lat and long API of google maps. Plus user experience is better if you can show his/her location on a map. No need to bother about the updation of user location or frisking with android api. Let google maps handle the internals for you.
@emmby may have got it resolved in his app but for future reference a look at Google maps API for location specific stuff is what I recommend to fellow developers.
Edit: Link for displaying user location in google maps
我的做法如下:
mFinalLocation
)更好。以下是服务代码。您可以根据需要的位置更新频率来运行它。
Here's what I do:
mFinalLocation
).onDestroy()
method of service, stop listening for location updates for each of the provider.Below is the code for service. You can run it based upon frequency of location update you need.
在 Activity 类中创建一个自定义方法:
创建一个 UserDefined 类名称 LocationGetter:-
In the Activity Class makes a customized method :
Make a UserDefined Class name LocationGetter:-
其中一些答案现在已经过时了,所以我回答,
some of these ans are now out of date, so im answering,
通过使用 FusedLocationProviderApi,它是最新的 API,也是 Android 中获取位置的可用可能性中最好的。
将其添加到 build.gradle 文件中,
您可以通过此 url 获取完整的源代码
http://javapapers.com/android/android-location-fused-provider/
By using FusedLocationProviderApi which is the latest API and the best among the available possibilities to get location in Android.
add this in build.gradle file
you can get full source code by this url
http://javapapers.com/android/android-location-fused-provider/
最近重构获取了代码的位置,学习了一些好的思路,终于实现了一个比较完善的库和Demo。
完整代码: https ://github.com/bingerz/FastLocation/blob/master/fastlocationlib/src/main/java/cn/bingerz/fastlocation/FastLocation.java
*每次请求完成位置时,最好去掉Updates,否则手机状态栏会一直显示定位图标。
Recently refactored to obtain the location of the code, learn some good ideas, and finally achieved a relatively perfect library and Demo.
Complete code: https://github.com/bingerz/FastLocation/blob/master/fastlocationlib/src/main/java/cn/bingerz/fastlocation/FastLocation.java
*Each request to complete the location, it is best to removeUpdates, otherwise the phone status bar will always display the positioning icon.
看到所有答案后,提出问题(最简单且稳健)。我只点击了库 Android-ReactiveLocation。
当我制作一个位置跟踪应用程序时。然后我意识到,通过电池优化来处理位置跟踪是非常典型的。
因此,我想告诉那些不想通过未来的优化来维护其位置代码的新手和开发人员。使用这个库。
放入应用程序级别 build.gradle 的依赖项
使用此库的优点:
After seeing all the answers, and question (Simplest and Robust). I got clicked about only library Android-ReactiveLocation.
When i made an location tracking app. Then i realized that its very typical to handle location tracking with optimised with battery.
So i want tell freshers and also developers who don't want to maintain their location code with future optimisations. Use this library.
Dependencies to put in app level build.gradle
Pros to use this lib: