Android 找到 GPS 位置一次,显示加载对话框
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3486055/
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 find GPS location once, show loading dialog
提问by Daniel Bowden
I am writing an app that requires the user's current location (lastknownlocation won't be very helpful) and displays a list of all the closest "items" to them taken from the database.
我正在编写一个应用程序,它需要用户的当前位置(lastknownlocation 不会很有帮助)并显示从数据库中获取的所有最接近它们的“项目”的列表。
I have got the finding of the closest items working well but only using a hardcoded latitude and longitude location for the time being but now it is time to implement finding the actual location.
我已经找到了最接近的项目,但目前仅使用硬编码的纬度和经度位置,但现在是实现查找实际位置的时候了。
Can anyone provide an example of how to have the app find the current fine location in the background and have the app wait. I only need the location once not updates as the person moves. I have implemented a location listener however I understand getting a GPS fix can be slow. I have seen other examples using last known location or implementing the location listener which continues to run and update however as my Activity needs the location coordinates before it can display anything the app just crashes. I need to show a Progress Dialog while its searching.
任何人都可以提供一个示例,说明如何让应用程序在后台找到当前的好位置并让应用程序等待。我只需要一次位置,不会随着人的移动而更新。我已经实现了一个位置监听器,但是我知道获取 GPS 定位可能很慢。我已经看到其他示例使用最后一个已知位置或实现继续运行和更新的位置侦听器,但是因为我的 Activity 需要位置坐标才能显示应用程序崩溃的任何内容。我需要在搜索时显示一个进度对话框。
How can I have the locationlistener run once in the background and then remove location updates once it finds the location. I need the rest of the application to wait until it has a GPS location or timeout after say 20-30seconds. I would like a ProgressDialog up so the user knows that something is going on, but it just has to be the spinning loading animation not a percentage or anything. If possible I would like the user to be able to cancel the dialog if they are sick of waiting which then they can search by typing suburb etc instead.
如何让位置侦听器在后台运行一次,然后在找到位置后删除位置更新。我需要应用程序的其余部分等待它有 GPS 位置或在 20-30 秒后超时。我想要一个 ProgressDialog up 以便用户知道正在发生的事情,但它必须是旋转加载动画而不是百分比或任何东西。如果可能的话,我希望用户能够在他们厌倦等待时取消对话,然后他们可以通过键入郊区等进行搜索。
I have been trying to do it with threads but it is getting way more complicated than I feel it should be and still not working anyway. On iPhone this is much more simple?
我一直在尝试用线程来做这件事,但它变得比我认为的更复杂,而且仍然无法正常工作。在 iPhone 上,这要简单得多?
Can anyone provide a nice way of doing this, I have been ripping my hair out for a week on this and it is really putting me behind schedule for the rest of the app completion date.
任何人都可以提供一个很好的方法来做到这一点,我已经在这个问题上扯了一个星期,这真的让我在应用程序完成日期的剩余时间里落后于计划。
In summary I want to:
* Find current coordinates
* Show Progress Dialog while getting location
* Have app be able to wait for successful location or give up after a certain time?
* If Successful: Dismiss Progress Dialog and use coordinates to run my other methods for finding items closeby.
* If Failed to get location: Dismiss Progress Dialog and show error message, and encourage user to use menu to go to Search Activity.
* Use these coordinates if the user chooses map view from the menu, to show current location on the map and pins dropped at all the nearby items by using their coordinates from the database.
总之,我想:
* 查找当前坐标
* 在获取位置时显示进度对话框
* 是否有应用程序能够等待成功定位或在一段时间后放弃?
* 如果成功:关闭进度对话框并使用坐标运行我的其他方法来查找附近的项目。
* 如果无法获取位置:关闭进度对话框并显示错误消息,并鼓励用户使用菜单转到搜索活动。
* 如果用户从菜单中选择地图视图,则使用这些坐标,以显示地图上的当前位置,并使用数据库中的坐标在附近的所有项目上放置图钉。
Thanks guys, I hope I have explained myself well enough. Any questions just ask, I will be checking back regularly as I am keen to get this part completed. Cheers
谢谢大家,我希望我已经足够好地解释了自己。任何问题都可以问,我会定期回来查看,因为我很想完成这部分。干杯
EDIT
Code as requested
根据要求编辑代码
locationList activity file
locationList 活动文件
protected void onStart()
{
super.onStart();
// ....
new LocationControl().execute(this);
}
private class LocationControl extends AsyncTask<Context, Void, Void>
{
private final ProgressDialog dialog = new ProgressDialog(branchAtmList.this);
protected void onPreExecute()
{
this.dialog.setMessage("Determining your location...");
this.dialog.show();
}
protected Void doInBackground(Context... params)
{
LocationHelper location = new LocationHelper();
location.getLocation(params[0], locationResult);
return null;
}
protected void onPostExecute(final Void unused)
{
if(this.dialog.isShowing())
{
this.dialog.dismiss();
}
useLocation(); //does the stuff that requires current location
}
}
public LocationResult locationResult = new LocationResult()
{
@Override
public void gotLocation(final Location location)
{
currentLocation = location;
}
};
LocationHelper class
LocationHelper 类
package org.xxx.xxx.utils;
import java.util.Timer;
/*
imports
*/
public class LocationHelper
{
LocationManager locationManager;
private LocationResult locationResult;
boolean gpsEnabled = false;
boolean networkEnabled = false;
public boolean getLocation(Context context, LocationResult result)
{
locationResult = result;
if(locationManager == null)
{
locationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
}
//exceptions thrown if provider not enabled
try
{
gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
}
catch (Exception ex) {}
try
{
networkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
}
catch (Exception ex) {}
//dont start listeners if no provider is enabled
if(!gpsEnabled && !networkEnabled)
{
return false;
}
if(gpsEnabled)
{
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps);
}
if(networkEnabled)
{
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork);
}
GetLastLocation();
return true;
}
LocationListener locationListenerGps = new LocationListener() {
public void onLocationChanged(Location location)
{
locationResult.gotLocation(location);
locationManager.removeUpdates(this);
locationManager.removeUpdates(locationListenerNetwork);
}
public void onProviderDisabled(String provider) {}
public void onProviderEnabled(String provider) {}
public void onStatusChanged(String provider, int status, Bundle extra) {}
};
LocationListener locationListenerNetwork = new LocationListener() {
public void onLocationChanged(Location location)
{
locationResult.gotLocation(location);
locationManager.removeUpdates(this);
locationManager.removeUpdates(locationListenerGps);
}
public void onProviderDisabled(String provider) {}
public void onProviderEnabled(String provider) {}
public void onStatusChanged(String provider, int status, Bundle extra) {}
};
private void GetLastLocation()
{
locationManager.removeUpdates(locationListenerGps);
locationManager.removeUpdates(locationListenerNetwork);
Location gpsLocation = null;
Location networkLocation = null;
if(gpsEnabled)
{
gpsLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
}
if(networkEnabled)
{
networkLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
}
//if there are both values use the latest one
if(gpsLocation != null && networkLocation != null)
{
if(gpsLocation.getTime() > networkLocation.getTime())
{
locationResult.gotLocation(gpsLocation);
}
else
{
locationResult.gotLocation(networkLocation);
}
return;
}
if(gpsLocation != null)
{
locationResult.gotLocation(gpsLocation);
return;
}
if(networkLocation != null)
{
locationResult.gotLocation(networkLocation);
return;
}
locationResult.gotLocation(null);
}
public static abstract class LocationResult
{
public abstract void gotLocation(Location location);
}
}
This really seems like a big effort just to get the current location once? I do not require updates or anything? Is there not a simpler way of having the application wait for a result? I have been stuck on this for so long.
仅仅为了获得一次当前位置,这真的似乎是一个很大的努力吗?我不需要更新或任何东西?有没有更简单的方法让应用程序等待结果?我已经坚持了这么久。
采纳答案by Mathias Conradt
Use an AsyncTaskand use both network_provider as well as gps_provider, which means two listeners. gps takes longer to get a fix, maybe sometimes a minute and only works outdoors, while network gets a location pretty fast.
使用AsyncTask并同时使用network_provider 和 gps_provider,这意味着两个侦听器。gps 需要更长的时间才能修复,有时可能需要一分钟,而且只能在户外使用,而网络可以很快找到位置。
A good code example is here: What is the simplest and most robust way to get the user's current location on Android?
这里有一个很好的代码示例:在 Android 上获取用户当前位置的最简单、最可靠的方法是什么?
For AsyncTask, look http://developer.android.com/reference/android/os/AsyncTask.html
对于 AsyncTask,请查看http://developer.android.com/reference/android/os/AsyncTask.html
There are also many code example here on SO for it, for example here: Android Show a dialog until a thread is done and then continue with the program
SO上也有很多代码示例,例如这里: Android Show a dialog until a thread is done and then continue to the program
EDIT: code concept:
编辑:代码概念:
add class variable
添加类变量
boolean hasLocation = false;
call in onCreate (not in AsyncTask):
调用 onCreate(不在 AsyncTask 中):
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
then in locationListener.onLocationChanged, change the value once a location is found:
然后在 locationListener.onLocationChanged 中,找到位置后更改值:
boolean hasLocation = false;
AsyncTask: leave as it is, but don't call
AsyncTask:保持原样,但不要调用
LocationHelper location = new LocationHelper();
location.getLocation(params[0], locationResult);
there, instead do
在那里,而不是做
Long t = Calendar.getInstance().getTimeInMillies();
while (!hasLocation && Calendar.getInstance().getTimeInMillies()-t<30000)) {
Thread.Sleep(1000);
};
probably with a delay in between would be sufficient.
可能中间有延迟就足够了。
回答by Daniel Bowden
I still don't like how this works at all and it seems way more complicated than it should be but until someone provides a better way I have it working for now...
我仍然根本不喜欢它的工作原理,它似乎比它应该的复杂得多,但是直到有人提供更好的方法我现在才能让它工作......
If someone comes across this and suggest a much better cleaner result to just get the user's current location coordinates just once then stop looking that would be greatly appreciated!!
如果有人遇到这个问题并建议一个更好的更清晰的结果来只获取用户的当前位置坐标一次,然后停止寻找,将不胜感激!
private LocationControl locationControlTask;
private boolean hasLocation = false;
LocationHelper locHelper;
From onCreate() I call
从 onCreate() 我打电话
locHelper = new LocationHelper();
locHelper.getLocation(context, locationResult);
locationControlTask = new LocationControl();
locationControlTask.execute(this);
I then have a a private class LocationControl
然后我有一个私有类 LocationControl
private class LocationControl extends AsyncTask<Context, Void, Void>
{
private final ProgressDialog dialog = new ProgressDialog(activityname.this);
protected void onPreExecute()
{
this.dialog.setMessage("Searching");
this.dialog.show();
}
protected Void doInBackground(Context... params)
{
//Wait 10 seconds to see if we can get a location from either network or GPS, otherwise stop
Long t = Calendar.getInstance().getTimeInMillis();
while (!hasLocation && Calendar.getInstance().getTimeInMillis() - t < 15000) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
};
return null;
}
protected void onPostExecute(final Void unused)
{
if(this.dialog.isShowing())
{
this.dialog.dismiss();
}
if (currentLocation != null)
{
useLocation();
}
else
{
//Couldn't find location, do something like show an alert dialog
}
}
}
Then a locationResult..
然后一个 locationResult..
public LocationResult locationResult = new LocationResult()
{
@Override
public void gotLocation(final Location location)
{
currentLocation = new Location(location);
hasLocation = true;
}
};
Also to avoid you pulling your hair out like I did for ages remember to stop the locationcontrol task if someone leaves the activity early and also stop location updates to stop the GPS from running when the user leaves. In onStop() do something like this:
同样为了避免你像我多年来所做的那样拉扯你的头发,如果有人提前离开活动,记得停止位置控制任务,并在用户离开时停止位置更新以阻止 GPS 运行。在 onStop() 中做这样的事情:
locHelper.stopLocationUpdates();
locationControlTask.cancel(true);
Also stopLocationUpdates in the Location Helper class does the following:
Location Helper 类中的 stopLocationUpdates 还执行以下操作:
public void stopLocationUpdates()
{
locationManager.removeUpdates(locationListenerGps);
locationManager.removeUpdates(locationListenerNetwork);
}
Good luck with it, I needed it...
祝你好运,我需要它......
回答by Carl
Instead of creating an AsyncTask why didn't you create a ProgressDialog box and dismiss it on public void gotLocation(final Location location){}
? You can also add a onCancelListener to the ProgressDialog box and cancel any current location requests.
为什么不创建一个 AsyncTask 而是创建一个 ProgressDialog 框并将其关闭public void gotLocation(final Location location){}
?您还可以将 onCancelListener 添加到 ProgressDialog 框并取消任何当前位置请求。