Я хочу получать широту и долготу местоположения при каждом вызове функции. Насколько я понял, лучший способ сделать это - оставить обновление местоположения на несколько секунд, чтобы получить правильное исправление, а затем отключить его, но я не могу заставить его работать в моем приложении.
До сих пор мне удавалось получать последнее известное местоположение телефона при каждом вызове функции displayData, но мне не удалось преодолеть все ошибки, которые появляются, когда я пытаюсь перейти на requestLocationUpdates. Что именно я здесь делаю, так это вызываю функцию displayData, когда есть входящие данные от устройства Bluetooth, чтобы получить местоположение и записать данные + местоположение в файл.
Может ли кто-нибудь мне помочь, потому что все руководства показывают, как что-то запускать при обновлении местоположения, но я не хочу этого делать. Я просто хочу периодически менять местоположение ...
private void displayData(final byte[] byteArray) {
try {
mFusedLocationClient.getLastLocation()
.addOnSuccessListener(this, new OnSuccessListener<Location>() {
@Override
public void onSuccess(Location location) {
// Got last known location. In some rare situations this can be null.
if (byteArray != null) {
String data = new String(byteArray);
tv.setText(n/2 + " measurements since startup...");
n += 1;
if (location != null) {
double lat = location.getLatitude();
double lng = location.getLongitude();
latitude = String.valueOf(lat);
longitude = String.valueOf(lng);
}
try
{
FileWriter fw = new FileWriter(textfile,true); //the true will append the new data
if (writeDate()) {
fw.write("\n");
fw.write(stringDate);
fw.write(data); //appends the string to the file
}
else {
fw.write(data); //appends the string to the file
fw.write(" - ");
fw.write(latitude);
fw.write(",");
fw.write(longitude);
}
fw.close();
}
catch(IOException ioe)
{
System.err.println("IOException: " + ioe.getMessage());
}
// find the amount we need to scroll. This works by
// asking the TextView's internal layout for the position
// of the final line and then subtracting the TextView's height
final int scrollAmount = tv.getLayout().getLineTop(
tv.getLineCount())
- tv.getHeight();
// if there is no need to scroll, scrollAmount will be <=0
if (scrollAmount > 0)
tv.scrollTo(0, scrollAmount);
else
tv.scrollTo(0, 0);
}
}
});
} catch (SecurityException e) {
// lets the user know there is a problem with the gps
}
}
Это может быть оправдано, потому что получение местоположения является асинхронным, и ваш displayData(), по-видимому, должен быть синхронным и не ждать завершения какой-либо другой операции. Но вы знаете свое приложение лучше.
Спасибо, Маркус. Мне тоже нравится твой подход. Если я хочу сэкономить заряд батареи, я могу установить значение minTime (для обновления местоположения), эквивалентное периоду повторения displayData, и я буду в порядке, не так ли? Если я получаю обновленное местоположение «вне» displayData, я могу даже оставить этот код как есть и использовать последнее известное местоположение, которое будет довольно точным, не так ли?
Да, «последнее известное местоположение» будет таким же хорошим (таким же), как и последнее местоположение, возвращенное функцией обратного вызова onLocationChanged(). Теоретически все могло быть иначе, если какое-то другое приложение тоже запрашивает обновления местоположения. Возможно даже с "худшими" настройками. Тогда, возможно, более безопасным способом было бы сохранить полученное значение в onLocationChanged(). Я на самом деле не тестировал этот сценарий.




Вот что я понимаю о вашей проблеме:
Старайтесь не думать о «функции, которая возвращает текущее местоположение телефона», потому что это подразумевает, что это простая синхронная операция, которая дает ответ без блокировки. Здесь мы не можем этого сделать.
Вместо этого я предлагаю вам думать об этом больше как о FSM, поскольку вам нужно произвольное количество времени (возможно, несколько секунд, возможно, больше) между моментом, когда вы звоните displayData(), и временем, когда вы начинаете получать исправления GPS в реальном времени. Другими словами, displayData() не создает местоположение напрямую; это приведет в движение цепочку событий, которая в конечном итоге приведет к тому, что вы получите местоположение.
Вам нужно будет использовать requestLocationUpdates() (или аналогичный метод):
private void displayData(final byte[] byteArray) {
//This call turns the GPS on, and returns immediately:
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, new LocationListener() {
//This function gets called some time after displayData() returns (possibly
//*way* after). It executes on the UI thread.
public void onLocationChanged(Location location) {
locationManager.removeUpdates(this); //Shut down the GPS
//(Execute the remainder of your onSuccess() logic here.)
//Now our state machine is complete, and everything is cleaned up.
//We are ready for the next call to displayData().
}
public void onStatusChanged(String provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
);
}
Туда,
displayData() возвращается немедленно)Вы можете рассмотреть некоторые улучшения этой схемы:
requestLocationUpdates(), если displayData() вызывается до того, как предыдущий запрос был разрешенonSuccess(), больше не доступны, т.Большое Вам спасибо. Я попробую и расскажу вам, но в вашем примере я думаю, что onLocationChanged выполняется только один раз (и это будет во многих метрах от фактического местоположения, не так ли?). Или мне что-то не хватает, и onLocationChanged возвращается после того, как хотя бы раз хорошо поработал? Если нет, я бы хотел, чтобы onLocationChanged запускался несколько раз (секунд), чтобы лучше исправить это, прежде чем записывать местоположение, поэтому я думаю, я мог бы попробовать что-то вроде того, что предлагает Маркус в своем комментарии?
Я не тестировал этот код. Но поскольку указан GPS_PROVIDER, я не думаю, что он даст вам устаревшее исправление. При первом срабатывании onLocationChanged() должна быть высокая точность. Но ваше предложение (например, счет до 2 перед вызовом removeUpdates()) или предложение @ markus-kauppinen также являются вполне допустимыми способами.
Я следовал подходу Маркуса Кауппинена, который запрашивал обновления местоположения в интервале времени, который подходит моему приложению, а затем просто использовал последнее известное местоположение при поступлении данных по Bluetooth. Поэтому я просто добавил в свою деятельность следующее:
LocationRequest mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(30000);
mLocationRequest.setFastestInterval(10000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationCallback mLocationCallback = new LocationCallback();
// Register the listener with the Location Manager to receive location updates
try {
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback,
null /* Looper */);
}
catch (SecurityException e) {
// lets the user know there is a problem with the gps
}
Возможно, вы могли бы разделить получение / поддержание местоположения и звонок
displayData(). Просто создайте переменную для последнего местоположения и используйте ее вdisplayData(). Затем позаботьтесь о поддержании актуального местоположения отдельно в зависимости от того, насколько точным является абсолютное требование и с какой скоростью устройство должно двигаться. Если скорость высока и местоположение должно быть точным, вы, вероятно, можете просто запросить обновления местоположения и продолжать их получать. В противном случае вы можете просто периодически обновлять, запрашивая обновления, получая одно или несколько, а затем отменяя их для экономии заряда батареи.