Intereting Posts
Каков наилучший способ приема данных с датчиков через плату arduino на устройство Android? Android получает разницу в миллисекундах между двумя датами 12/24-часовой режим конфликта BackUpAgentHelperClass не вызван Подписание приложения, но не публикация на Android-рынке JSONObject не работает для Android 2.3, но отлично работает с Android 4.2, почему? Панель прогресса Android в списке всегда неопределенна Как настроить настраиваемую строку заголовка TextView Динамически динамически в Android? Android AWS SDK версии 2.2.1 – gethttprequest лишен, не в состоянии найти замену Stop scrollView в середине прокрутки Как показать уведомление, даже приложение не работает Нажмите кнопку Android, чтобы увидеть другое сообщение Toast, зависящее от количества кликов Как узнать использование памяти текущего запущенного приложения в android? ОТКЛЮЧИТЬ автоматический перевод списка магазинов в Google Play JNI ОБНАРУЖЕН ОШИБКУ В ПРИМЕНЕНИИ

Android – проблемы API провайдера Fused Location со спутниковой информацией (счет, сигнал и т. Д.)

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

Просматривая вокруг StackExchange и Google и везде, я пришел к выводу, что практически невозможно получить информацию о спутниках с использованием API Fused Location (хорошая работа там Google).

Метод, используемый большинством людей, заключается в том, чтобы фактически использовать LocationManager рядом с местом Fused, чтобы получить статус GPS. Мой первый вопрос приходит сюда: как мы можем быть на 100% уверены, что номера, предоставленные LocationManager, синхронизированы с тем, что дала нам Fused Location? Использует ли плавающее местоположение Менеджер внутри?

И теперь вопрос. Приложение использует «всегда включенную» липкую услугу, чтобы поднять позиции независимо от того, что. Когда спутников нет, все работает по назначению. Поместите устройство в положение, где он может видеть спутники, у него нет блокировки. С помощью отладчика GpsStatus.getSatellites () содержит пустой список. Теперь, не перемещая устройство, я запускаю приложение Compass (по Catch.com, так как его много), который имеет схему компаса типа GPS. Это блокирует спутники и довольно быстро, и с этого момента в моем приложении также сообщается о спутниках. Если компас закрыт, приложение застряло на последнем номере, предоставленном компасом !!! Устройство, которое я лично использую для тестирования, – это Nexus 7 2013 с последними официальными обновлениями (Android 6.0.1).

Вот какой код:

public class BackgroundLocationService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, GpsStatus.Listener, LocationListener { // Constants here.... private GoogleApiClient mGoogleApiClient; private LocationRequest mLocationRequest; private LocationManager locationManager; // Flag that indicates if a request is underway. private boolean mInProgress; private NotificationManagement myNotificationManager; private Boolean servicesAvailable = false; //And other variables here... @Override public void onCreate() { super.onCreate(); myNotificationManager = new NotificationManagement(getApplicationContext()); myNotificationManager.displayMainNotification(); mInProgress = false; // Create the LocationRequest object mLocationRequest = LocationRequest.create(); // Use high accuracy mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); // Set the update interval mLocationRequest.setInterval(PREFERRED_INTERVAL); // Set the fastest update interval mLocationRequest.setFastestInterval(FASTEST_INTERVAL); servicesAvailable = servicesConnected(); locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); locationManager.addGpsStatusListener(this); setUpLocationClientIfNeeded(); } /** * Create a new location client, using the enclosing class to * handle callbacks. */ protected synchronized void buildGoogleApiClient() { this.mGoogleApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); } private boolean servicesConnected() { // Check that Google Play services is available int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this); // If Google Play services is available if (ConnectionResult.SUCCESS == resultCode) { return true; } else { return false; } } public int onStartCommand(Intent intent, int flags, int startId) { super.onStartCommand(intent, flags, startId); if (!servicesAvailable || mGoogleApiClient.isConnected() || mInProgress) return START_STICKY; setUpLocationClientIfNeeded(); if (!mGoogleApiClient.isConnected() || !mGoogleApiClient.isConnecting() && !mInProgress) { mInProgress = true; mGoogleApiClient.connect(); } return START_STICKY; } private void setUpLocationClientIfNeeded() { if (mGoogleApiClient == null) buildGoogleApiClient(); } public void onGpsStatusChanged(int event) { } // Define the callback method that receives location updates @Override public void onLocationChanged(Location location) { simpleGPSFilter(location); } // Other fancy and needed stuff here... /** * "Stupid" filter that utilizes experience data to filter out location noise. * @param location Location object carrying all the needed information */ private void simpleGPSFilter(Location location) { //Loading all the required variables int signalPower = 0; satellites = 0; // Getting the satellites mGpsStatus = locationManager.getGpsStatus(mGpsStatus); Iterable<GpsSatellite> sats = mGpsStatus.getSatellites(); if (sats != null) { for (GpsSatellite sat : sats) { if (sat.usedInFix()) { satellites++; signalPower += sat.getSnr(); } } } if (satellites != 0) signalPower = signalPower/satellites; mySpeed = (location.getSpeed() * 3600) / 1000; myAccuracy = location.getAccuracy(); myBearing = location.getBearing(); latitude = location.getLatitude(); longitude = location.getLongitude(); Log.i("START OF CYCLE", "START OF CYCLE"); Log.i("Sat Strength", Integer.toString(signalPower)); Log.i("Locked Sats", Integer.toString(satellites)); // Do the math for the coordinates distance /* * Earth's radius at given Latitude. * Formula: Radius = sqrt( ((equatorR^2 * cos(latitude))^2 + (poleR^2 * sin(latitude))^2 ) / ((equatorR * cos(latitude))^2 + (poleR * sin(latitude))^2) * IMPORTANT: Math lib uses radians for the trigonometry equations so do not forget to use toRadians() */ Log.i("Lat for Radius", Double.toString(latitude)); double earthRadius = Math.sqrt((Math.pow((EARTH_RADIUS_EQUATOR * EARTH_RADIUS_EQUATOR * Math.cos(Math.toRadians(latitude))), 2) + Math.pow((EARTH_RADIUS_POLES * EARTH_RADIUS_POLES * Math.cos(Math.toRadians(latitude))), 2)) / (Math.pow((EARTH_RADIUS_EQUATOR * Math.cos(Math.toRadians(latitude))), 2) + Math.pow((EARTH_RADIUS_POLES * Math.cos(Math.toRadians(latitude))), 2))); Log.i("Earth Radius", Double.toString(earthRadius)); /* * Calculating distance between 2 points on map using the Haversine formula (arctangent writing) with the following algorithm * latDifference = latitude - lastLatitude; * lngDifference = longitude - lastLongitude; * a = (sin(latDifference/2))^2 + cos(lastLatitude) * cos(latitude) * (sin(lngDifference/2))^2 * c = 2 * atan2( sqrt(a), sqrt(1-a) ) * distance = earthRadius * c */ double latDifference = latitude - lastLatitude; double lngDifference = longitude - lastLongitude; double a = Math.pow((Math.sin(Math.toRadians(latDifference / 2))), 2) + (Math.cos(Math.toRadians(lastLatitude)) * Math.cos(Math.toRadians(latitude)) * Math.pow((Math.sin(Math.toRadians(lngDifference / 2))), 2)); double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); double distance = earthRadius * c; Log.i("New point distance", Double.toString(distance)); // Filter logic // Make an initial location log if ((!isInit) && (myAccuracy < ACCEPTED_ACCURACY)) { isInit = true; lastLatitude = latitude; lastLongitude = longitude; logLocations(location); } else { // Satellite lock (use of GPS) on the higher level if (satellites == 0) { // Accuracy filtering at the second level if (myAccuracy < ACCEPTED_ACCURACY) { if ((distance > ACCEPTED_DISTANCE)) { lastLatitude = latitude; lastLongitude = longitude; logLocations(location); Log.i("Location Logged", "No Sats"); /* // Calculate speed in correlation to perceived movement double speed = distance / (PREFERRED_INTERVAL / 1000); // TODO: Need to make actual time dynamic as the fused location does not have fixed timing if (speed < ACCEPTED_SPEED) { lastLatitude = latitude; lastLongitude = longitude; logLocations(location); } */ } } } else if ((satellites < 4) && (signalPower > ACCEPTED_SIGNAL)) { if (myAccuracy < (ACCEPTED_ACCURACY + 50)) { logLocations(location); Log.i("Location Logged", "With Sats"); } } else { if (myAccuracy < (ACCEPTED_ACCURACY + 100)) { lastSpeed = mySpeed; lastBearing = myBearing; lastLatitude = latitude; lastLongitude = longitude; logLocations(location); Log.i("Location Logged", "With Good Sats"); } } } Log.i("END OF CYCLE", "END OF CYCLE"); } private void logLocations(Location location) { String myprovider = "false"; String temp = timestampFormat.format(location.getTime()); MySQLiteHelper dbHelper = new MySQLiteHelper(getApplicationContext()); try { dbHelper.createEntry(latitude, longitude, allschemes, temp, mySpeed, myAccuracy, myBearing, myprovider, satellites); } catch (Exception e) { e.printStackTrace(); } CheckAutoArrive(String.valueOf(latitude), String.valueOf(longitude)); } 

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

В связи с тем, что приложение Compass может заставить систему получить спутники, а мое приложение не может. Есть ли способ на самом деле заставить читать службы местоположения? Возможно ли, что Fused Location фактически использует GPS, но менеджер местоположений не знает об этом?

Наконец, я хотел бы упомянуть, что приложение было протестировано в других устройствах (телефонах, а не планшетах) с различными версиями Android и, похоже, работает правильно.

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

EDIT: Мои актуальные вопросы были скрыты в тексте, чтобы выложить их:

1) Имеются ли данные о местоположении из плавного местоположения и остальная часть данных GPS, которые мы можем, по-видимому, получить только из диспетчера местоположений в синхронизации или есть возможность получить местоположение, но неправильное количество заблокированных спутников для конкретной точки ?

2) Что может быть причиной странного поведения, когда приложение не может получить блокировку для спутников, но если блокировка исходит из другого приложения, она, по-видимому, правильно используется приложением? Чтобы сделать это еще более странным, это происходит с Nexus 7 (Android 6.0.1), но не с другими устройствами, протестированными с различными версиями Android.

Из моего понимания:

1)

FusedLocationApi возвращает новое местоположение каждый раз, когда есть новое чтение от любого соответствующего провайдера на клиентском устройстве (WiFi, CellTower, GPS, Bluetooth). Это чтение сливается с предыдущей оценкой местоположения (возможно, с использованием расширенного фильтра Калмана или аналогичного). Результирующее обновление местоположения – это плавная оценка нескольких источников, поэтому метаданные от отдельных поставщиков не привязаны.

Таким образом, данные о местоположении, которые вы получаете из API, могут совпадать с чистым показанием GPS, полученным от LocationManager (если GPS был самым последним и релевантным источником местоположения), но это не обязательно. Следовательно, количество спутников, полученных из последнего чистого считывания GPS, может относиться к последнему местоположению, возвращенному FusedLocationApi, или оно может и не быть.

Вкратце:

Нет гарантии, что чтение местоположения, полученное из LocationManager, синхронизируется с местоположением из FusedLocationApi .

2)

Во-первых: Чтобы определить основную причину этой проблемы, вам нужно протестировать несколько устройств в нескольких местах. Поскольку вы спросили

Что может быть причиной странного поведения?

Я брошу одну теорию: предположив, что LocationManager и FusedLocationApi работают полностью отдельно, LocationManager может изо всех сил пытаться получить исправление, потому что вы полагаетесь только на GPS. Попробуйте использовать NETWORK_PROVIDER в дополнение к GPS, чтобы ускорить время от времени до исправления (таким образом, чтобы LocationManager мог использовать Assisted GPS ). Другие приложения (например, приложение Compass) почти наверняка делают это, что объясняет, почему они получают более быстрое исправление. Примечание. После того, как вы начнете получать данные GPS, вы, конечно же, можете отменить регистрацию сетевого провайдера. Или вы держите его, но просто игнорируете его обновления.

Это одно из возможных объяснений странного поведения. Вероятно, вы знаете, что поведение местоположения зависит от устройства, ОС, набора микросхем GPS, прошивки и местоположения, в котором вы находитесь, поэтому, если вы планируете идти вручную (т. Е. Не использовать FusedLocationApi), вам придется поэкспериментировать совсем немного.


В дополнение к ответам, позвольте мне дать упрямый ответ на вашу проблему (нужно взять с солью ;-): Я думаю, вы пытаетесь объединить две вещи, которые были сделаны для очень разных вариантов использования, и не Которые должны сочетаться.

Получение количества спутников является чем-то совершенно техническим. Никакой конечный пользователь никогда не будет заинтересован в такой информации, если ваше приложение не учит их GNSS. Если вы хотите записать его для целей внутренней аналитики, это нормально, но тогда вы должны иметь дело с ситуациями, когда эта информация недоступна.

Сценарий 1. По какой-то причине вы решите, что вам абсолютно необходимы подробные (технические) особенности показаний GPS. В таком случае, постройте логику самостоятельно, старую школьную дорогу . Т.е. попросите показания GPS (и, возможно, ускорить этот процесс с помощью сетевого провайдера) через LocationManager, затем скомбинируйте этот материал самостоятельно. Однако в этом случае никогда не касайтесь FusedLocationApi . Хотя это может показаться старомодным и загадочным в наши дни, использование LocManager с логикой слияния DIY по-прежнему имеет смысл для небольшого числа вариантов использования. Вот почему API все еще существует.

Сценарий 2 : вы просто хотите получать быстрые и точные обновления по месту нахождения клиента. В этом случае укажите желаемую частоту и точность обновления, и пусть FusedLocationApi выполнит свою работу . FusedLocationApi проделал долгий путь в последние годы, и есть вероятность, что в наши дни будет проще и лучше выяснить, как получить информацию о местоположении, чем любая логика DIY. Это связано с тем, что получение информации о местоположении является очень гетерогенной проблемой, которая зависит от возможностей клиентского устройства (чипсета, прошивки, ОС, GPS, WiFi, GSM / LTE, Bluetooth и т. Д.), А также от физического окружения (WiFi / CellTower / Bluetooth-сигналы рядом, внутри или снаружи, ясное небо или городской каньон и т. Д.). В этом случае не трогайте поставщиков вручную . Если вы это сделаете, не ожидайте каких-либо значимых выводов относительно связи между показаниями отдельных поставщиков и плавными результатами.


Два заключительных замечания:

  • Android предоставляет Location.distanceTo () и Location.distanceBetween () , поэтому нет необходимости реализовывать формулу Haversine в коде.

  • Если вам просто нужны быстрые и надежные обновления из FusedLocationApi, я написал небольшой класс утилиты, называемый LocationAssistant, который упрощает настройку и делает большую часть тяжелой работы для вас.