Подтвердить что ты не робот

Android: requestLocationUpdates обновляет местоположение максимум каждые 45 секунд

Фон

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

Проблема

Когда я тестирую его (provider = LocationManager.NETWORK_PROVIDER), вызов requestLocationUpdates(provider, minTime, minDistance, locationListener) с любым minTime < 45000 имеет тот же эффект, что и minTime = 45000, т.е. я получаю обновления с интервалом ровно 45 секунд.
Я знаю, что минимальный параметр времени - это только "подсказка", но это не воспринимается как подсказка для моего приложения. Я получаю обновления с интервалом, указанным до тех пор, пока этот интервал не пройдет менее 45 секунд. Кажется, что минимальное время в 45 секунд между обновлениями местоположения жестко запрограммировано на Android, но это было бы странно. Плюс я никогда не слышал об этой проблеме раньше, и я не смог найти ее здесь, на Stackoverflow.

Поскольку я не могу получать частые обновления, моим обходным решением (на данный момент) является ручное вызов requestLocationUpdates, когда требуется новое местоположение, а затем просто используйте первое доступное местоположение. Чтобы сделать это с небольшими интервалами, я использую handler.postDelayed(myRunnable, updateInterval) для задержки вызовов, а myRunnable затем выполняет вызов requestLocationUpdates. Однако этот метод работает только около 50 (по-видимому, случайных) процентов времени.

Кто-нибудь знает о проблеме, и есть ли способ ее исправить? Или мой единственный вариант установить minTime = 0 и просто надеяться на лучшее?

Исходный код

Вот исходный код myRunnable, метод run(), который я регулярно вызываю вручную с помощью handler.postDelayed(myRunnable, updateInterval):

public class MyRunnable implements Runnable {
    private LocationManager manager;
    private LocationListener listener;

    @Override
    public void run() {
        // This is called everytime a new update is requested
        // so that only one request is running at a time.
        removeUpdates();

        manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

        listener = new LocationListener() {
            @Override
            public void onLocationChanged(Location loc) {
                location = loc;
                latitude = loc.getLatitude();
                longitude = loc.getLongitude();
                accuracy = Math.round(loc.getAccuracy());

                handler.sendMessage(Message.obtain(handler, KEY_MESSAGE_LOCATION_CHANGED));

                checkForArrival();
            }

            // Other overrides are empty.
        };

        if(!arrived)
            manager.requestLocationUpdates(provider, updateInterval, 0, listener);
    }

    /**
     * Removes location updates from the LocationListener.
     */
    public void removeUpdates() {
        if(!(manager == null || listener == null))
            manager.removeUpdates(listener);
    }

    // Another method for "cleaning up" when the user has arrived.
}


И вот мой handler:

handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch(msg.what) {
            case KEY_MESSAGE_LOCATION_CHANGED:
                if(myRunnable != null) {
                    myRunnable.removeUpdates();
                    handler.postDelayed(myRunnable, updateInterval);
                }
                break;
            }
        }
    };


Дополнительная информация

Вся информация об обновлении местоположения выполняется в службе.

Я несколько раз прочитал документ, у Google возникла проблема, и попробовал различные другие способы обхода проблемы. Ничего не делает.

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

Любая помощь будет очень оценена!

4b9b3361

Ответ 1

Вы можете установить minTime для любого значения. Тем не менее, вы получите обновление только после того, как будет доступно новое местоположение. Сеть обновляется только каждые 45 секунд на каждом телефоне, который у меня есть. Это, по-видимому, является ограничением сетевого провайдера. Если вы хотите получать более частое обновление, используйте поставщика GPS. В зависимости от оборудования GPS вы должны получить максимальную скорость обновления около 4 Гц.

Ответ 2

Вы совершенно правы, минимальное время 45 секунд отображается в Android.

Кажется, что это исходный код класса NetworkLocationProvider, когда он все еще находился в ядре Android:

http://www.netmite.com/android/mydroid/frameworks/base/location/java/com/android/internal/location/NetworkLocationProvider.java

Посмотрите на переменную:

private static final long MIN_TIME_BETWEEN_WIFI_REPORTS = 45 * 1000; // 45 seconds

И метод:

@Override
public void setMinTime(long minTime) {
    if (minTime < MIN_TIME_BETWEEN_WIFI_REPORTS) {
        mWifiScanFrequency = MIN_TIME_BETWEEN_WIFI_REPORTS;
    } else {
        mWifiScanFrequency = minTime;
    }
    super.setMinTime(minTime);
}

Теперь NetworkLocationProvider выходит из ядра Android, вы можете найти его в NetworkLocation.apk в /system/app

Вы можете найти объяснение, почему здесь неясно:

https://groups.google.com/forum/?fromgroups=#!topic/android-platform/10Yr0r2myGA

Но 45 секунд минут, похоже, все еще там. Посмотрите на эту декомпиляцию NetworkProvider:

http://android.fjfalcon.com/xt720/miui-trans/apk-decompiled/NetworkLocation/smali/com/google/android/location/NetworkLocationProvider.smali

.line 149
const-wide/32 v4, 0xafc8

iput-wide v4, p0, Lcom/google/android/location/NetworkLocationProvider;->mWifiScanFrequency:J

Как вы могли догадаться, если вы конвертируете 0xafc8 в десятичный, вы получите 45000 миллисекунд

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

Фактически для API геолокации существует ограничение на 100 запросов:

https://developers.google.com/maps/documentation/business/geolocation/#usage_limits

Но они, похоже, не соблюдают это правило в приложении "Карты Google". Если вы откроете его, и вы только активном сетевом расположении, вы можете заметить, что ваше местоположение обновляется гораздо чаще, чем 45 секунд.

Я заметил, что эта строка подозрительно частая (33 раза в секунду) в logcat, когда открываются Карты Google:

02-20 17: 12: 08.204: V/LocationManagerService (1733): getAllProviders

Я думаю, что Google Maps снова вызывает removeUpdates() и requestLocationUpdates(), чтобы получить новую позицию.

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

Ответ 3

У меня была аналогичная проблема. Я положил вызов locationManager.requestSingleUpdate() в конце onLocationChanged() и принудительно обновил его. Вы можете установить команду задержки, затем выполнить requestSingleUpdate, убедившись, что она содержит locationListener.

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