Как я могу получить текущее местоположение GPS каждый раз, когда вызывается функция?

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

До сих пор мне удавалось получать последнее известное местоположение телефона при каждом вызове функции 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(). Просто создайте переменную для последнего местоположения и используйте ее в displayData(). Затем позаботьтесь о поддержании актуального местоположения отдельно в зависимости от того, насколько точным является абсолютное требование и с какой скоростью устройство должно двигаться. Если скорость высока и местоположение должно быть точным, вы, вероятно, можете просто запросить обновления местоположения и продолжать их получать. В противном случае вы можете просто периодически обновлять, запрашивая обновления, получая одно или несколько, а затем отменяя их для экономии заряда батареи.

Markus Kauppinen 04.12.2018 15:23

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

Markus Kauppinen 04.12.2018 15:23

Спасибо, Маркус. Мне тоже нравится твой подход. Если я хочу сэкономить заряд батареи, я могу установить значение minTime (для обновления местоположения), эквивалентное периоду повторения displayData, и я буду в порядке, не так ли? Если я получаю обновленное местоположение «вне» displayData, я могу даже оставить этот код как есть и использовать последнее известное местоположение, которое будет довольно точным, не так ли?

vlamb 04.12.2018 20:06

Да, «последнее известное местоположение» будет таким же хорошим (таким же), как и последнее местоположение, возвращенное функцией обратного вызова onLocationChanged(). Теоретически все могло быть иначе, если какое-то другое приложение тоже запрашивает обновления местоположения. Возможно даже с "худшими" настройками. Тогда, возможно, более безопасным способом было бы сохранить полученное значение в onLocationChanged(). Я на самом деле не тестировал этот сценарий.

Markus Kauppinen 05.12.2018 09:51
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
4
327
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вот что я понимаю о вашей проблеме:

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

Старайтесь не думать о «функции, которая возвращает текущее местоположение телефона», потому что это подразумевает, что это простая синхронная операция, которая дает ответ без блокировки. Здесь мы не можем этого сделать.

Вместо этого я предлагаю вам думать об этом больше как о 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() возвращается немедленно)
  • Конечный автомат в конечном итоге сходится к ответу (при условии, что GPS работает)
  • GPS отключается, когда мы получаем необходимую информацию

Вы можете рассмотреть некоторые улучшения этой схемы:

  • Способ избежать повторного вызова requestLocationUpdates(), если displayData() вызывается до того, как предыдущий запрос был разрешен
  • Обработка случая, когда элементы пользовательского интерфейса, упомянутые в вашем методе onSuccess(), больше не доступны, т.
  • Отмена незавершенного запроса, если вам нужно очистить и т. д.

Большое Вам спасибо. Я попробую и расскажу вам, но в вашем примере я думаю, что onLocationChanged выполняется только один раз (и это будет во многих метрах от фактического местоположения, не так ли?). Или мне что-то не хватает, и onLocationChanged возвращается после того, как хотя бы раз хорошо поработал? Если нет, я бы хотел, чтобы onLocationChanged запускался несколько раз (секунд), чтобы лучше исправить это, прежде чем записывать местоположение, поэтому я думаю, я мог бы попробовать что-то вроде того, что предлагает Маркус в своем комментарии?

vlamb 04.12.2018 19:43

Я не тестировал этот код. Но поскольку указан GPS_PROVIDER, я не думаю, что он даст вам устаревшее исправление. При первом срабатывании onLocationChanged() должна быть высокая точность. Но ваше предложение (например, счет до 2 перед вызовом removeUpdates()) или предложение @ markus-kauppinen также являются вполне допустимыми способами.

greeble31 04.12.2018 19:57
Ответ принят как подходящий

Я следовал подходу Маркуса Кауппинена, который запрашивал обновления местоположения в интервале времени, который подходит моему приложению, а затем просто использовал последнее известное местоположение при поступлении данных по 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
    }

Другие вопросы по теме