Android находят местоположение GPS один раз, отображает диалоговое окно загрузки
Я пишу приложение, для которого требуется текущее местоположение пользователя (lastknownlocation не будет очень полезно) и отображает список всех ближайших "элементов" к ним, взятым из базы данных.
У меня есть нахождение ближайших элементов, работающих хорошо, но только с использованием жестко закодированного местоположения широты и долготы на данный момент, но теперь пришло время реализовать поиск фактического местоположения.
Может ли кто-нибудь представить пример того, как приложение может найти текущее точное местоположение в фоновом режиме и ждать приложения. Мне нужно только одно место, которое не обновляется по мере перемещения человека. Я реализовал приемник местоположения, но я понимаю, что исправление GPS может быть медленным. Я видел другие примеры, используя последнее известное местоположение, или внедряя прослушиватель местоположения, который продолжает работать и обновляется, однако, поскольку моей активности требуется координаты местоположения, прежде чем она сможет отобразить все, что приложение просто сработает. Мне нужно показать диалог выполнения во время его поиска.
Как я могу запустить диспетчер местоположений один раз в фоновом режиме, а затем удалить обновления местоположений после того, как он найдет местоположение. Мне нужно, чтобы остальная часть приложения подождала, пока у него не появится местоположение GPS или тайм-аут после 20-30 секунд. Мне нужен ProgressDialog, чтобы пользователь знал, что что-то происходит, но он просто должен быть анимацией вращающейся загрузки, а не процентом или чем-то еще. Если возможно, я хотел бы, чтобы пользователь мог отменить диалог, если им надоело ждать, а затем они могут искать, набрав пригород и т.д. Вместо этого.
Я пытаюсь сделать это с помощью потоков, но он становится намного сложнее, чем я считаю, что он должен быть и все равно не работает. На iPhone это намного проще?
Может ли кто-нибудь предоставить хороший способ сделать это, я разорвал свои волосы на неделю на этом, и это действительно заставляет меня отставать от графика на оставшуюся дату завершения приложения.
В резюме я хочу:
* Найти текущие координаты
* Показывать диалог выполнения при получении местоположения
* У приложения есть возможность ждать успешного местоположения или сдаваться через определенное время?
* If Successful: Dismiss Progress Dialog и используйте координаты для запуска моих других методов поиска близких объектов.
* Если не удалось получить местоположение: Отклонить диалог прогресса и показать сообщение об ошибке, а также побудить пользователя использовать меню для перехода к активности поиска.
* Используйте эти координаты, если пользователь выбирает отображение карты из меню, чтобы отображать текущее местоположение на карте и контакты, сброшенные во всех соседних элементах, используя их координаты из базы данных.
Спасибо, ребята, надеюсь, я достаточно хорошо объяснил. Любые вопросы просто спрашивают, я буду регулярно проверять, поскольку я заинтересован в том, чтобы эта часть была завершена.
Приветствия
ИЗМЕНИТЬ
Код по запросу
файл активности 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
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);
}
}
Это действительно похоже на большое усилие только для того, чтобы получить текущее местоположение один раз? Я не требую обновлений или чего-то еще? Нет ли более простого способа заставить приложение ждать результата? Я застрял на этом так долго.
Ответы
Ответ 1
Используйте AsyncTask и используйте как network_provider, так и gps_provider, что означает два слушателя. gps занимает больше времени, чтобы получить исправление, может быть, иногда минута и работает только на открытом воздухе, а сеть быстро находит место.
Хороший пример кода здесь: Каков самый простой и самый надежный способ получить текущее местоположение пользователя на Android?
Для AsyncTask посмотрите http://developer.android.com/reference/android/os/AsyncTask.html
Здесь также много примеров кода для SO, например:
Android Покажите диалог, пока поток не будет выполнен, а затем продолжите работу с программой
EDIT:
концепция кода:
добавить переменную класса
boolean hasLocation = false;
вызов в onCreate (не в AsyncTask):
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
то в locationListener.onLocationChanged измените значение после нахождения местоположения:
boolean hasLocation = false;
AsyncTask:
оставить как есть, но не вызывать
LocationHelper location = new LocationHelper();
location.getLocation(params[0], locationResult);
вместо этого do
Long t = Calendar.getInstance().getTimeInMillies();
while (!hasLocation && Calendar.getInstance().getTimeInMillies()-t<30000)) {
Thread.Sleep(1000);
};
вероятно, с задержкой между ними было бы достаточно.
Ответ 2
Мне все еще не нравится, как это работает вообще, и кажется, что это сложнее, чем должно быть, но пока кто-то не обеспечит лучший способ, с которым я сейчас работаю...
Если кто-то наткнется на это и предложит гораздо лучший результат, чтобы просто получить координаты текущего местоположения пользователя только один раз, тогда перестаньте смотреть, что было бы очень полезно!
private LocationControl locationControlTask;
private boolean hasLocation = false;
LocationHelper locHelper;
From onCreate() Я вызываю
locHelper = new LocationHelper();
locHelper.getLocation(context, locationResult);
locationControlTask = new LocationControl();
locationControlTask.execute(this);
Затем у меня есть закрытый класс 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
}
}
}
Затем значение locationResult..
public LocationResult locationResult = new LocationResult()
{
@Override
public void gotLocation(final Location location)
{
currentLocation = new Location(location);
hasLocation = true;
}
};
Кроме того, чтобы вы не вытаскивали волосы, как я делал на протяжении веков, помните, чтобы остановить работу по настройке местоположения, если кто-то рано покинет мероприятие, а также остановит обновления местоположения, чтобы остановить работу GPS при выходе пользователя. В onStop() выполните примерно так:
locHelper.stopLocationUpdates();
locationControlTask.cancel(true);
Также stopLocationUpdates в классе Location Helper выполняет следующие действия:
public void stopLocationUpdates()
{
locationManager.removeUpdates(locationListenerGps);
locationManager.removeUpdates(locationListenerNetwork);
}
Удачи вам, мне это нужно...
Ответ 3
Вместо того, чтобы создавать AsyncTask, почему вы не создали окно ProgressDialog и не отклонили его на public void gotLocation(final Location location){}
? Вы также можете добавить onCancelListener в поле ProgressDialog и отменить любые текущие запросы местоположения.