Место Android иногда слишком старое

У меня возникла странная проблема, когда я пытаюсь найти местоположение устройства в android.

Иногда он хорошо находит текущее местоположение, но иногда он продолжает возвращаться в прежнее место. И по-старому я имею в виду, как несколько дней и десятки или даже сотни километров от того места, где он должен быть расположен.

Я не знаю, что я делаю неправильно, я попробовал несколько разных способов получить местоположение, но кажется, что каждый метод имеет ту же проблему.

Самое странное, что это не происходит в каждом устройстве … или, по крайней мере, это то, что кажется. Samsung S3 и S4 наиболее сильно затронуты, но в моей связи 4 этого никогда не было.

Это мой код, возможно, вы видите что-то не так:

public void startSearchingLocation() { // Define a listener that responds to location updates locationListener = new LocationListener() { @Override public void onLocationChanged(Location location) { // Called when a new location is found by the network location // provider. makeUseOfNewLocation(location); } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @Override public void onProviderEnabled(String provider) { } @Override public void onProviderDisabled(String provider) { } }; String provider = getProvider(); /*I ignore the passive provider*/ if (provider == null || provider.contains(LocationManager.PASSIVE_PROVIDER)) { this.validProvider = false; } else { this.validProvider = true; } if (validProvider) { locationManager.requestLocationUpdates(provider, time, distance, locationListener); } } protected void makeUseOfNewLocation(Location location) { JSONObject obj = new JSONObject(); try { obj.put("latitude", location.getLatitude()); obj.put("longitude", location.getLongitude()); obj.put("provider", location.getProvider()); locationResult = obj; } catch (Exception e) { e.printStackTrace(); } } public JSONObject getLastKnownLocation() { if (locationResult != null) { return locationResult; } else { String provider = getProvider(); Location location = locationManager.getLastKnownLocation(provider); if (location != null) { JSONObject obj = new JSONObject(); try { obj.put("latitude", location.getLatitude()); obj.put("longitude", location.getLongitude()); obj.put("provider", location.getProvider()); return obj; } catch (Exception e) { e.printStackTrace(); } } } return null; } public String getProvider() { Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); criteria.setPowerRequirement(Criteria.POWER_LOW); criteria.setAltitudeRequired(false); criteria.setBearingRequired(false); criteria.setSpeedRequired(false); String provider = locationManager.getBestProvider(criteria, true); return provider; } 

благодаря

ПРИМЕЧАНИЕ. Это неплохое подключение к Интернету. Несколько пользователей начали жаловаться на эту проблему. Хотя приложения, которые используют геолокацию, работают нормально. Это должно быть что-то в моем коде, но я не могу понять, что. Самое странное, что он работает нормально на неделю или две, а затем он начинает происходить у многих пользователей одновременно

Я бы сказал, что проблема в

 criteria.setPowerRequirement(Criteria.POWER_LOW); 

Возможно, это просто возвращение пассивного провайдера. Я бы убрал это, теперь пользователи знают, что этот вид приложений потребляет аккумулятор, поэтому он не будет принудительным критерием.

В любом случае, у меня есть более сложный класс для поиска местоположения. Позволь мне объяснить.

Во-первых, отсюда я использую эту замечательную функцию, чтобы определить, лучше ли одно считывание местоположения, чем текущее местоположение.

  /** * @param location * The new Location that you want to evaluate * @param currentBestLocation * The current Location fix, to which you want to compare the new * one */ protected boolean isBetterLocation(Location location, Location currentBestLocation) { if (currentBestLocation == null) { // A new location is always better than no location return true; } // Check whether the new location fix is newer or older long timeDelta = location.getTime() - currentBestLocation.getTime(); boolean isSignificantlyNewer = timeDelta > TWO_MINUTES; boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES; boolean isNewer = timeDelta > 0; // If it's been more than two minutes since the current location, use // the new location // because the user has likely moved if (isSignificantlyNewer) { return true; // If the new location is more than two minutes older, it must be // worse } else if (isSignificantlyOlder) { return false; } // Check whether the new location fix is more or less accurate int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation .getAccuracy()); boolean isLessAccurate = accuracyDelta > 0; boolean isMoreAccurate = accuracyDelta < 0; boolean isSignificantlyLessAccurate = accuracyDelta > 200; // Check if the old and new location are from the same provider boolean isFromSameProvider = isSameProvider(location.getProvider(), currentBestLocation.getProvider()); // Determine location quality using a combination of timeliness and // accuracy if (isMoreAccurate) { return true; } else if (isNewer && !isLessAccurate) { return true; } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) { return true; } return false; } /** Checks whether two providers are the same */ private boolean isSameProvider(String provider1, String provider2) { if (provider1 == null) { return provider2 == null; } return provider1.equals(provider2); } 

Затем я создаю свой собственный класс, который реализует LocationListener (активность или вспомогательный класс, до вас). Я просто рассматриваю gps и поставщика сети, но он легко расширяется

 public class LocationObserver implements LocationListener { LocationManager lm; boolean gps_enabled = false; boolean network_enabled = false, network_connected = false; Context context; Long timeout; int minTime; int minDistance; Handler handler = new Handler(); private Location currentLocation = null; public LocationObserver(Context pContext, int minTime, int minDistance, long timeout) { this.context = pContext; this.timeout = timeout; this.minDistance = minDistance; this.minTime = minTime; } 

Я создаю метод start, где я считаю, какой из них является лучшим поставщиком, или если я могу слушать более одного

  public void start() { if (lm == null) lm = (LocationManager) context .getSystemService(Context.LOCATION_SERVICE); // exceptions will be thrown if provider is not permitted. try { gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER); } catch (Exception ex) { //dont worry yet } try { network_enabled = lm .isProviderEnabled(LocationManager.NETWORK_PROVIDER); ConnectivityManager cm = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); network_connected = activeNetwork != null && activeNetwork.isConnectedOrConnecting(); } catch (Exception ex) { //dont wory yet } //now, lets see what happend, //don't start listeners if no provider is enabled if (!gps_enabled && !network_enabled) { //nothing enabled, alert the user to enable any provide //Settings.ACTION_LOCATION_SOURCE_SETTINGS; } else { // one provider is enabled, and the other one is not if (gps_enabled) { // gps enabled, network disabled lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, minTime, minDistance, this); //Consider asking the user to also enable network location ( Settings.ACTION_LOCATION_SOURCE_SETTINGS;= } else { // gps disabled, network enabled // check if actually there is a conection if (network_connected) { lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, minTime, minDistance, this); //OK, Network is working, //consider asking the user to enable also gps (Settings.ACTION_LOCATION_SOURCE_SETTINGS;) } //if network is not enabled, having the network location enabled is useles else { //ask the user to connect to any network ( Settings.ACTION_WIRELESS_SETTINGS) } } } //retrieve the lastKnownLocation (we will see this function later) and call the callback to start using it handler.postDelayed(new Runnable() { @Override public void run() { Location l = getLastKnownLocation(); onLocationChanged(l); } }, timeout); } 

Мы создали свой собственный getLastKnownLocation (), который учитывает всех разрешенных поставщиков и возвращает наилучшее местоположение

  public Location getLastKnownLocation() { Location net_loc = null, gps_loc = null; if (gps_enabled) gps_loc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER); if (network_enabled) net_loc = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); // if there are both values use the best one if (gps_loc != null && net_loc != null) { if (isBetterLocation(gps_loc, net_loc)) return gps_loc; else return net_loc; } else if (gps_loc != null) { return gps_loc; } else if (net_loc != null) { return net_loc; } else return null; } 

И, наконец, мы пишем обратный вызов onLocationChanged, который провайдеры будут вызывать с любым обновлением. Поскольку все провайдеры назовут это, вероятно, ближайшее место хуже, чем тот, который у нас уже есть, поэтому мы также сравниваем их

 public synchronized void onLocationChanged(Location location) { if (location == null || currentLocation == null || isBetterLocation(location, currentLocation)) { currentLocation = location; //do whatever you need with the new location } } } 

Кроме того, то, что я использую, – это продолжать проверку таймером, если местоположение появилось после первого вызова getlastknowlocation. Если пройдет определенное время, я проверю все, что нужно, чтобы узнать, какие поставщики включены, или попросите пользователя снова включить отключенных.

Кроме того, некоторым людям нравится полагаться непосредственно в Play Services Location Apis, где вам не нужно беспокоиться о провайдерах и не нужно сосредотачиваться на деталях базовой технологии местоположения. https://developer.android.com/google/play-services/location.html

 Location location = locationManager.getLastKnownLocation(provider); 

Вызывает проблему. getLastKnownLocation(provider) предоставляет последнее местоположение, которое собирается или используется любым приложением на основе местоположения в смартфоне пользователя.

Вы можете использовать Sharedpreferences для сохранения данных о местоположении в своем приложении, чтобы вы могли использовать его как lastknownlocation, когда это необходимо.

Попробуйте таким образом:

И используйте bestProvider

 // Getting LocationManager object from System Service LOCATION_SERVICE LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); // Creating a criteria object to retrieve provider Criteria criteria = new Criteria(); // Getting the name of the best provider String provider = locationManager.getBestProvider(criteria, true); // Getting Current Location From GPS Location location = locationManager.getLastKnownLocation(provider); if(location!=null) { onLocationChanged(location); } locationManager.requestLocationUpdates(provider, 20000, 0, this); 

Расположение AFAIK происходит от «лучшего» источника, доступного для Android-устройства. Это означает, что GPS-возможности или местоположение отображаются в браузере (через службы определения местоположения Google). Поскольку каждое устройство отличается, вы получите разные результаты. У вас есть специальное устройство, поддерживающее GPS, предпочтительнее использовать 3G (или лучше комм) – вы получите лучшие результаты поиска таким образом. Я думаю, что это ошибка как таковая, просто реальность попытки разместить ваше устройство в любой сети, к которой он подключен.

Я думаю, вы используете getLastKnownLocation() когда вы этого не ожидаете. Ваша реализация getLastKnownLocation() использует последний результат из диспетчера местоположений, если он доступен, или последнее известное местоположение, если ничего не доступно. Таким образом, если ваши пользователи отключат службы определения местоположения, ваше приложение будет постоянно использовать последнее место, которое он видел, из makeUseOfNewLocation() или последнего местоположения, которое видел телефон, из locationManager.getLastKnownLocation(provider) . Это объясняет поведение, которое вы видите, что код постоянно возвращает одно и то же старое местоположение.

Чтобы решить эту проблему, вы можете использовать обратные вызовы onProviderEnabled / onProviderDisabled, чтобы уведомить ваше приложение о том, что он не должен продолжать использовать lastKnownLocation. Вы также можете проверить, подключены ли ваши службы определения местоположения до того, как вы используете местоположение, используя locationManager.isProviderEnabled () или locationClient.isConnected () и предложите пользователю их повторно использовать.

Попробуй это:-

  public class MainActivity extends Activity implements LocationListener{ protected LocationManager locationManager; protected LocationListener locationListener; protected Context context; TextView txtLat; String lat; String provider; protected String latitude,longitude; protected boolean gps_enabled,network_enabled; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); txtLat = (TextView) findViewById(R.id.textview1); locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this); } @Override public void onLocationChanged(Location location) { txtLat = (TextView) findViewById(R.id.textview1); txtLat.setText("Latitude:" + location.getLatitude() + ", Longitude:" + location.getLongitude()); } @Override public void onProviderDisabled(String provider) { Log.d("Latitude","disable"); } @Override public void onProviderEnabled(String provider) { Log.d("Latitude","enable"); } @Override public void onStatusChanged(String provider, int status, Bundle extras) { Log.d("Latitude","status"); } } 

Также убедитесь, что в файле манифеста указаны следующие разрешения: –

  <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> 

Если вам требуется точное исправление положения, явным образом задайте провайдеру местоположения для чтения GPS (да, он использует больше батареи).

criteria.setPowerRequirement(Criteria.POWER_LOW);

Это будет использовать пассивное местоположение, используя сигналы Wi-Fi и сигнальные башни для мобильных телефонов в том районе, где вы находитесь, и я думаю, что это где-то не так!

POWER_LOW использует географическое местоположение IP любого сигнала Wi-Fi / мобильного телефона рядом с вами.

Согласно http://www.ipligence.com/geolocation, местоположение моего статического IP-адреса составляет 170 км к северу от моего фактического местоположения. Итак, если вы используете мой Wi-Fi-сигнал, чтобы получить фиксированное положение, он отключится на 170 км.

Даже сигналы мобильного телефона будут определять ваше место только при триангуляции сигнальных вышек в этой области и не являются наиболее точными, поскольку они перекрывают друг друга, чтобы сохранить уровень сигнала.

Играя с этим в приложении Android, я сказал, что идея пассивного провайдера местоположения хороша в теории, а не в реальности для позиционирования.

И в ваших критериях есть конфликт:

 criteria.setAccuracy(Criteria.ACCURACY_FINE); criteria.setPowerRequirement(Criteria.POWER_LOW); 

ACCURACY_FINE означает использование GPS в качестве locationprovider (используйте тяжелую батарею).
POWER_LOW означает использование low powerusage locationprovider (поэтому НЕ используйте GPS)

Я предлагаю вам внедрить новый API LocationClient . Все алгоритмы, касающиеся того, какой поставщик выбрать для вас, Он всегда использует лучший поставщик, доступный благодаря плавному провайдеру. Он также использует другие датчики, чтобы получить максимально точное местоположение.

На самом деле у меня такая же проблема. Я вижу это не только в коде, но и в поведении с другими устройствами.

Карты Google на моем HTC Sensation показывают мне места с прошлой недели, ведьма, как оказалось, в последний раз, когда я запускаю приложение и его единственное приложение, использующее локации на моем телефоне.

Поэтому я пришел к выводу, что эта денежная наличность – это то, как управляется на своем драйвере.

Я решил эту проблему, проигнорировав эти результаты. Я всегда помню последние данные о местоположении, которые я получил и знаю, чтобы игнорировать его, когда это не имеет значения.