Отслеживайте местоположение пользователя, как это делает Google

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

В основном я использую FusedLocationProviderApi для получения обновлений местоположения. Это действительно полезно и просто в использовании. Проблема в том, что мне нужно очень часто запрашивать местоположения, и это очень быстро разряжает батарею (хотя, возможно, часть использования батареи может быть связана с сетевыми операциями для отправки местоположения на сервер). Однако мне нужны частые обновления только во время перемещения пользователя.

Итак, я ищу что-то похожее на Google для отслеживания пользователей Android (как мы можем видеть в LocationHistory). ). Кто-нибудь знает, доступны ли где-то местоположения, полученные Google со смартфона? Или, может быть, стратегия для реализации чего-то подобного?


person Tinadm    schedule 24.04.2015    source источник
comment
Предложение по снижению потребления батареи, вы можете использовать обнаружение активности, чтобы определить, как часто вам нужно определять положение. В связи с этим я могу порекомендовать github.com/mcharmas/Android-ReactiveLocation, в создание которого я внес свой вклад. часть обнаружения активности. Библиотека также значительно сокращает количество строк кода, необходимых для получения объединенных локаций.   -  person cYrixmorten    schedule 24.04.2015
comment
Должен сказать, что я не знал об ActivityRecognitionApi и похоже, что это именно то, что мне нужно. Попробую это. Спасибо!   -  person Tinadm    schedule 24.04.2015
comment
Нет проблем :) по моему опыту, он работает на удивление хорошо, несмотря на низкое потребление батареи.   -  person cYrixmorten    schedule 24.04.2015
comment
@cYrixmorten У меня возникли проблемы с поиском примеров и документации для ActivityDetectionApi. Везде, кажется, указывает на эту ссылку (developer.android.com/training/location/index. html), но я нигде не могу найти пример... Вы знаете, где я могу его найти?   -  person Tinadm    schedule 24.04.2015


Ответы (3)


Предложение по снижению потребления батареи, вы можете использовать обнаружение активности, чтобы определить, как часто вам нужно определять положение. В связи с этим могу порекомендовать https://github.com/mcharmas/Android-ReactiveLocation, к которому Я внес свой вклад в часть обнаружения активности. Библиотека также значительно сокращает количество строк кода, необходимых для получения объединенных локаций.

Библиотека включает простой пример использования здесь: https://github.com/mcharmas/Android-ReactiveLocation/blob/master/sample/src/main/java/pl/charmas/android/reactivelocation/sample/MainActivity.java

Как вы написали в комментарии, найти хорошие примеры использования ActivityDetectionApi непросто. Это также было одной из причин, почему я добавил его в библиотеку. На самом деле документация, которая была доступна в то время в Google, устарела, поскольку они обновили API сервисов Google Play, но не учебные пособия.

У меня нет хороших указателей на учебники, не использующие библиотеку, но я могу предоставить фрагмент своего кода с помощью ReactiveLocation. Этот код работает в службе, поэтому он отслеживает текущую активность независимо от того, находится приложение в фокусе или нет:

private void requestFilteredActivityUpdates() {

    ReactiveLocationProvider locationProvider = new ReactiveLocationProvider(getApplicationContext());
    filteredActivitySubscription = locationProvider.getDetectedActivity(0).doOnError(new Action1<Throwable>() {
        @Override
        public void call(Throwable throwable) {
            String message = "Error on activitySubscription: " + throwable.getMessage();
            Log.e(TAG, message, throwable);
            Crashlytics.logException(throwable);
        }
    }).onErrorReturn(new Func1<Throwable, ActivityRecognitionResult>() {
        @Override
        public ActivityRecognitionResult call(Throwable throwable) {
            List<DetectedActivity> list = new ArrayList<DetectedActivity>();
            list.add(new DetectedActivity(DetectedActivity.UNKNOWN, 0));
            return new ActivityRecognitionResult(list, System.currentTimeMillis(), SystemClock.elapsedRealtime());
        }
    }).filter(new Func1<ActivityRecognitionResult, Boolean>() {
        @Override
        public Boolean call(ActivityRecognitionResult activityRecognitionResult) {

            DetectedActivity detectedActivity = activityRecognitionResult.getMostProbableActivity();

            boolean highConfidence =  detectedActivity.getConfidence() > 75;


            DetectedActivity previousActivity = ActivityDetectionModule.Recent.getDetectedActivity();
            boolean isNewActivity = detectedActivity.getType() != previousActivity.getType();
            boolean hasHigherConfidence = detectedActivity.getConfidence() > previousActivity.getConfidence();


            return mJustStarted || (highConfidence && (isNewActivity || hasHigherConfidence)); 
        }
    }).subscribe(new Action1<ActivityRecognitionResult>() {
        @Override
        public void call(ActivityRecognitionResult activityRecognitionResult) {

            DetectedActivity detectedActivity = activityRecognitionResult.getMostProbableActivity();

            Log.i(TAG, "Activity changed or increased in confidence:");

            Log.i(TAG, "New: " + ActivityDetectionModule.getNameFromType(detectedActivity.getType()) + " confidence: " + detectedActivity.getConfidence());

        }
    });
}

И в onDestroy() я звоню

public void unsubscribeActivityUpdates() {
    unsubscribe(filteredActivitySubscription);
}

private void unsubscribe(Subscription subscription) {
    if (subscription != null && !subscription.isUnsubscribed()) {
        Log.i(TAG, "Unsubscribe activity updates");
        try {
            subscription.unsubscribe();
        } catch (Exception e) {
            e.printStackTrace();
        }
        subscription = null;
    }
}

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

person cYrixmorten    schedule 24.04.2015

Вы можете использовать LocationRequest для ваших нужд.

LocationRequest location= new LocationRequest();

Я уверен, что конструктор принимает значение. Проверьте документацию по Android.

Таким образом, с запросом местоположения у вас есть такие функции, как

Установите интервал, установите наименьшее смещение, которое извлекает местоположение каждые несколько секунд или метров, которые он переместил.

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

И все, что вам нужно сделать в конце, это запросить обновления местоположения из слитного API и передать запрос в качестве параметра.

person TheAnimatrix    schedule 24.04.2015
comment
Я знаю о LocationRequest. Как я уже сказал, я использую FusedLocationProviderApi для получения местоположений. Это означает, что я уже использовал запросы с указанным интервалом для получения обновлений местоположения. Я хочу, чтобы какая-то разумная стратегия изменяла интервал обновления запроса в соответствии с движением пользователя, как это делает Google (более быстрые обновления, когда пользователь перемещается, более медленные обновления, когда пользователь остановлен и т. д.). - person Tinadm; 24.04.2015
comment
Ой! Извините за это ... У меня есть идея, но дайте мне несколько источников, чтобы быть уверенным. - person TheAnimatrix; 24.04.2015
comment
Ждать ! Как я уже упоминал в ответе ... вы пытались установить наименьшее смещение, это то, что вы ищете. Он не отправляет больше обновлений, когда вы едете быстро, просто вы быстрее встречаете параметр расстояния, когда двигаетесь быстро, скажем, если это 50 метров. - person TheAnimatrix; 24.04.2015
comment
Это правда. Я не использовал наименьшее смещение, потому что думал, что интервал обновления имеет приоритет над смещением. Что действительно произошло, так это то, что я использовал очень маленькое смещение, и даже когда я стоял на месте, вариации GPS превышали мой порог смещения. Может быть, подход с наименьшим смещением может быть тем, что мне нужно. Я проведу еще несколько тестов и дам вам знать - person Tinadm; 24.04.2015

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

Возможно, вы захотите использовать requestLocationUpdates, в частности эта версия, которая лучше всего подходит для использования с фоновой задачей . В LocationRequest вы можете использовать setInterval для определения интервала обновления.

Что касается расхода заряда батареи: очевидно, что постоянно открывать сетевые сокеты (или держать их открытыми) для отправки данных о вашем местоположении — не лучшее решение. Ваше приложение должно определить, когда действительно необходимо отправить обновление на ваш сервер.

Google не предлагает API для прямого извлечения истории местоположений, это то, что они оставляют для себя. Вы можете запросить файл местоположения kml и прочитать его, но это еще менее подходит для мониторинга в реальном времени.

person tony    schedule 24.04.2015
comment
Как я уже сказал, я уже использую FusedLocationApi. Однако вы правы в том, что постоянно открывать сетевые сокеты - не очень хорошая идея. Я изменю это в будущих версиях приложения. - person Tinadm; 24.04.2015
comment
Да, вы использовали, но используете ли вы requestLocationUpdates() так, как я описал? Как вы писали, вы очень часто запрашиваете, что звучит так, как будто вы довольно часто запрашиваете текущее местоположение, а не получаете трансляцию с использованием PendingIntent. - person tony; 24.04.2015
comment
Да. Это именно то, что я делаю. Я получаю обновления через PendingIntent. Я ищу более разумный способ настроить частоту обновлений, а не способ запрашивать обновления. - person Tinadm; 24.04.2015