Android GPS 超时
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2992567/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android GPS timeout
提问by Scott Saunders
Edit:I'm rewriting this question because I apparently wasn't clear.
编辑:我正在重写这个问题,因为我显然不清楚。
Sometimes the GPS service on Android phones takes a long time to get a fix. Sometimes it's fast, sometimes it takes hours. I know and accept this.
有时,Android 手机上的 GPS 服务需要很长时间才能修复。有时它很快,有时需要几个小时。我知道并接受这一点。
I have an application that does many things. One of the things it must do is allow the user to click a button to send their current coordinates to a server. What I need are the coordinates of the phone when the user clicks the buttonor within a reasonably short time thereafter.
我有一个可以做很多事情的应用程序。它必须做的一件事是允许用户单击按钮将其当前坐标发送到服务器。我需要的是当用户单击按钮时或在此后相当短的时间内手机的坐标。
Because I know that getting a GPS fix is not instant and I know that it could take minutes or hours (during which the user has moved a great distance), I need to code a timeout for this feature. For this feature, it is simply not acceptable to upload the GPS location of the user three minutes (for example) after they clicked the button. It's fine if it takes 45 seconds, not okay if it takes 75 seconds. It's fine to give the user an error notification if the feature failed to get a location fast enough.
因为我知道获得 GPS 修复不是即时的,而且我知道它可能需要几分钟或几小时(在此期间用户移动了很远的距离),我需要为此功能编码超时。对于此功能,在用户单击按钮后三分钟(例如)上传用户的 GPS 位置是完全不可接受的。如果需要 45 秒就可以了,如果需要 75 秒就不行。如果该功能未能足够快地获取位置,则可以向用户发出错误通知。
I need a feature to 'get the GPS location and send it to the server, unless it takes more than one minute'.
我需要一个功能来“获取 GPS 位置并将其发送到服务器,除非需要超过一分钟”。
My original code is below. I have changed some things since posting it. I have added a Timer in the onStartCommand() method. I start a TimerTask that after 60 seconds will call my stop() method. At the beginning of the onLocationChanged() method, I cancel the TimerTask.
我的原始代码如下。自从发布后我改变了一些东西。我在 onStartCommand() 方法中添加了一个计时器。我启动了一个 TimerTask,它会在 60 秒后调用我的 stop() 方法。在 onLocationChanged() 方法的开头,我取消了 TimerTask。
My question is: Is the Timer scheme a good way of implementing this timeout? Is there a better way?
我的问题是: Timer 方案是实现此超时的好方法吗?有没有更好的办法?
Original question:
原问题:
I'm writing an Android application that, among other things, needs to send the current GPS coordinates to a server when the user tells it to. From a context menu, I run the service below. The service is a LocationListener and requests updates from the LocationManager. When it gets a location (onLocationChanged()), it removes itself as a listener and sends the coordinates off to the server. All of this is working.
我正在编写一个 Android 应用程序,除其他外,当用户告诉它时,需要将当前 GPS 坐标发送到服务器。从上下文菜单中,我运行下面的服务。该服务是一个 LocationListener 并从 LocationManager 请求更新。当它获得一个位置 (onLocationChanged()) 时,它会将自己作为侦听器移除,并将坐标发送到服务器。所有这些都在起作用。
However, if GPS coordinates are not quickly available, my service just keeps running until it gets some. It holds up the UI with a progress dialog, which is annoying. Worse, if the user has moved since starting the service, the first GPS coordinates might be wrong and the app will send bad data to the server.
但是,如果 GPS 坐标不能很快获得,我的服务就会一直运行,直到得到一些。它用一个进度对话框来支撑 UI,这很烦人。更糟糕的是,如果用户在启动服务后移动了,第一个 GPS 坐标可能是错误的,应用程序将向服务器发送错误数据。
I need a timeout on the service. Is there a good way to do that? I'm not very experienced with threads. I think I can run a Runnable in the onStartCommand() method that will somehow count down 30 seconds and then, if there is no GPS result yet, call my service's stop() method. Does that sound like the best way to do this?
我需要服务超时。有没有好的方法可以做到这一点?我对线程不是很有经验。我想我可以在 onStartCommand() 方法中运行一个 Runnable ,它会以某种方式倒计时 30 秒,然后,如果还没有 GPS 结果,则调用我的服务的 stop() 方法。这听起来是不是最好的方法?
Alternatively, is it possible to tell if the GPS cannot get a fix? How would I go about doing that?
或者,是否可以判断 GPS 是否无法修复?我该怎么做?
Edit:To further clarify, I'm looking for the best way to "give up" on getting a Location after some amount of time.
编辑:为了进一步澄清,我正在寻找在一段时间后“放弃”获取位置的最佳方法。
public class AddCurrentLocation extends Service implements LocationListener {
Application app;
LocationManager mLocManager;
ProgressDialog mDialog;
@Override
public int onStartCommand(Intent intent, int arg0, int arg1) {
app = getApplication();
// show progress dialog
if (app.getScreen() != null) {
mDialog = ProgressDialog.show(app.getScreen(), "", "Adding Location. Please wait...", true);
}
// find GPS service and start listening
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
mLocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
String bestProvider = mLocManager.getBestProvider(criteria, true);
mLocManager.requestLocationUpdates(bestProvider, 2000, 0, this);
return START_NOT_STICKY;
}
private void stop() {
mLocManager.removeUpdates(this);
if (mDialog != null) {
mDialog.dismiss();
}
stopSelf();
}
@Override
public void onLocationChanged(Location location) {
// done with GPS stop listening
mLocManager.removeUpdates(this);
sendLocation(location); // method to send info to server
stop();
}
// other required methods and sendLocation() ...
}
采纳答案by Robby Pond
That's not really how it works. It will consistently take that long in most situations to get a GPS fix. But from that point on each update (every 2 sec in your code)will be the person's current position. And the first fix you get will be the person's current position, so the data will not be "out of date".
这不是它的工作原理。在大多数情况下,获得 GPS 定位总是需要那么长时间。但是从那时起,每次更新(在您的代码中每 2 秒)将是此人的当前位置。您获得的第一个修复将是此人的当前位置,因此数据不会“过时”。
Another thing. If you are running this code in a service you shouldn't block the UI with a progress dialog and definitely not from the Service. That is a memory leak waiting to happen. You should only show progress if it is something that might take 5 sec at the most and is running in a thread in the Activity. Another option is to show the progress dialog in the title bar, and still let the user interact with the app (which is why you use a service anyway). Showing progresses for a long period of time really isn't that User Friendly. Especially if they somehow change orientation (maybe on accident) and then your app crashes because of the service handle to the dialog and they have to start over.
另一件事。如果您在服务中运行此代码,则不应使用进度对话框阻止 UI,而且绝对不能从服务中阻止。这是等待发生的内存泄漏。如果它最多可能需要 5 秒并且正在活动的线程中运行,则您应该只显示进度。另一种选择是在标题栏中显示进度对话框,并仍然让用户与应用程序交互(这就是您无论如何都要使用服务的原因)。长时间显示进度确实不是那么用户友好。特别是如果他们以某种方式改变了方向(可能是偶然的),然后你的应用程序因为对话框的服务句柄而崩溃,他们必须重新开始。
Take a look at the Google I/O 2010 appto see a great example of how an activity should work with a service. It uses a service to pull back data, and shows a progress in the title while the service is doing some work. And still lets you do other things in the app.
查看Google I/O 2010 应用程序,了解 Activity 应如何与服务协同工作的绝佳示例。它使用服务来拉回数据,并在服务做一些工作时在标题中显示进度。并且仍然允许您在应用程序中执行其他操作。
回答by DJC
Scott, there are many factors that affect how long a first fix can take - or even whether a fix can be achieved, the most common being physical obstacles between the device and satellites (sucha s buildings, canyon walls, etc).
Scott,有很多因素会影响首次修复需要多长时间——甚至是否可以实现修复,最常见的是设备和卫星之间的物理障碍(例如建筑物、峡谷壁等)。
You can't control how long it takes for the GPS engine to deliver a fix, but you can tell how its doing, including time of first fix:
您无法控制 GPS 引擎提供修复所需的时间,但您可以知道它是如何进行的,包括首次修复的时间:
locationManager.addGpsStatusListener(gpsListener);
// this reports on the status of the GPS engine, but does not enable additional controls
private static final GpsStatus.Listener gpsListener = new GpsStatus.Listener() {
public void onGpsStatusChanged(int event) {
GpsStatus gpsStatus = locationManager.getGpsStatus(null);
switch (event) {
case GpsStatus.GPS_EVENT_STARTED:
Log.i(TAG, "onGpsStatusChanged(): GPS started");
break;
case GpsStatus.GPS_EVENT_FIRST_FIX:
Log.i(TAG, "onGpsStatusChanged(): time to first fix in ms = " + gpsStatus.getTimeToFirstFix());
break;
case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
// int maxSatellites = gpsStatus.getMaxSatellites(); // appears fixed at 255
// if (H.DEBUG) Log.d(TAG, "onGpsStatusChanged(): max sats = " + maxSatellites);
if (H.VERBOSE) Log.d(TAG, "onGpsStatusChanged(): ##,used,s/n,az,el");
Iterable<GpsSatellite>satellites = gpsStatus.getSatellites();
Iterator<GpsSatellite>satI = satellites.iterator();
while (satI.hasNext()) {
GpsSatellite satellite = satI.next();
if (H.VERBOSE) Log.d(TAG, "onGpsStatusChanged(): " + satellite.getPrn() + "," + satellite.usedInFix() + "," + satellite.getSnr() + "," + satellite.getAzimuth() + "," + satellite.getElevation());
// http://en.wikipedia.org/wiki/Global_Positioning_System: the almanac consists of coarse orbit and status information for each satellite
// http://en.wikipedia.org/wiki/Ephemeris: the positions of astronomical objects in the sky at a given time
// + "," + satellite.hasAlmanac() + "," + satellite.hasEphemeris());
}
break;
case GpsStatus.GPS_EVENT_STOPPED:
Log.i(TAG, "onGpsStatusChanged(): GPS stopped");
break;
}
}
};
Events will be generated as the engine attempts to listen to available satellites. On a recent test of this with light obstacles I found it took 22.4 seconds to get an initial fix, during which 24 SATELLITE_STATUS events reporting the gradual access of 8 satellites before sufficiently clean signals were received to achieve the fix. Here is the last event:
当引擎尝试侦听可用卫星时,将生成事件。在最近的一次轻障碍测试中,我发现获得初始定位需要 22.4 秒,在此期间,24 个 SATELLITE_STATUS 事件报告了 8 颗卫星的逐渐访问,然后才收到足够干净的信号以实现定位。这是最后一个事件:
06-08 23:23:25.147,D,GPS,22427,"onGpsStatusChanged(): ##,used,s/n,az,el" 06-08 23:23:25.147,D,GPS,22427,"onGpsStatusChanged(): 2,true,26.0,57.0,73.0" 06-08 23:23:25.147,D,GPS,22427,"onGpsStatusChanged(): 4,true,30.0,46.0,27.0" 06-08 23:23:25.147,D,GPS,22427,"onGpsStatusChanged(): 5,true,19.0,144.0,25.0" 06-08 23:23:25.155,D,GPS,22427,"onGpsStatusChanged(): 9,true,22.0,202.0,22.0" 06-08 23:23:25.155,D,GPS,22427,"onGpsStatusChanged(): 10,true,17.0,109.0,32.0" 06-08 23:23:25.155,D,GPS,22427,"onGpsStatusChanged(): 12,true,32.0,320.0,80.0" 06-08 23:23:25.155,D,GPS,22427,"onGpsStatusChanged(): 29,true,21.0,278.0,21.0" 06-08 23:23:25.155,D,GPS,22427,"onGpsStatusChanged(): 30,true,31.0,312.0,43.0" 06-08 23:23:25.163,D,GpsLocationProvider,1039,TTFF: 22457 06-08 23:23:25.194,I,GPS,22427,onGpsStatusChanged(): time to first fix in ms = 22457
06-08 23:23:25.147,D,GPS,22427,"onGpsStatusChanged(): ##,used,s/n,az,el" 06-08 23:23:25.147,D,GPS,22427,"onGpsStatusChanged (): 2,true,26.0,57.0,73.0" 06-08 23:23:25.147,D,GPS,22427,"onGpsStatusChanged(): 4,true,30.0,46.0,27.0" 06-08 23:23: 25.147,D,GPS,22427,"onGpsStatusChanged(): 5,true,19.0,144.0,25.0" 06-08 23:23:25.155,D,GPS,22427,"onGpsStatusChanged(): 9,0,20,22 ,22.0" 06-08 23:23:25.155,D,GPS,22427,"onGpsStatusChanged(): 10,true,17.0,109.0,32.0" 06-08 23:23:25.155,D,GPS,224 (): 12,true,32.0,320.0,80.0" 06-08 23:23:25.155,D,GPS,22427,"onGpsStatusChanged(): 29,true,21.0,278.0,21.0" 06-03:23 25.155,D,GPS,22427,"onGpsStatusChanged(): 30,true,31.0,312.0,43.0" 06-08 23:23:25.163,D,GpsLocationProvider,1039,TTFF: 22458:2320025.194,I,GPS,22427,onGpsStatusChanged():以毫秒为单位的首次修复时间 = 22457
Note that at fix time, you will be getting the current location, not where you once may have been. I think along with what you have already you can get there now. Or, check out how the pros do it here.
请注意,在固定时间,您将获得当前位置,而不是您曾经去过的位置。我认为连同你已经拥有的,你现在可以到达那里。或者,在这里查看专业人士是如何做到的。
回答by Shawn
There is a example about get GPS location with timeout.
有一个关于超时获取 GPS 位置的示例。
http://sikazi.blogspot.com/2010/09/android-gps-timeout.html#more
http://sikazi.blogspot.com/2010/09/android-gps-timeout.html#more
回答by John R.B. Palmer
I have been struggling with a similar issue and recently switched from a timer to an AlarmManager
, which appears to be much more robust. That might be overkill for your situation (I am using this for repeated location sampling), but you might want to at least use a Handler
instead of the timer. (Use Handler.postDelayed
.)
我一直在为一个类似的问题而苦苦挣扎,最近从计时器切换到了AlarmManager
,这似乎更加强大。对于您的情况,这可能是矫枉过正(我将其用于重复位置采样),但您可能至少希望使用 aHandler
而不是计时器。(使用Handler.postDelayed
。)