Перейти к содержанию
Fire Monkey от А до Я
  • 0

[Android] [XE7] Как получить GPS координаты без компонента?


brunnengi

Вопрос

Рекомендуемые сообщения

  • 0
  • Администраторы

Добрый вечер,

 

Можно задействовать сенсоры из RTL напрямую:

  1. Запросить менеджер сенсоров System.Sensors.TSensorManager.Current;
  2. Запросить у менеджера сенсоров список сенсоров по категории TSensorCategory.Location  TSensorManager.GetSensorsByFilter
  3. Выбрать из списка сенсоров необходимый. Проверив, доступные свойства TCustomLocationSensor.AvailableProperties, которые каждый может выдавать и другие характеристики сенсоров.
  4. Работать на прямую с выбранным сенсором локации TCustomLocationSensor

P.S. Но по сути вы получите тот же объект, что и в компоненте TLocationSensor.Sensor. Правда без использования непосредственно компонента.

Изменено пользователем Brovin Yaroslav
Ссылка на комментарий
  • 0
В 30.09.2014 в 23:57, Brovin Yaroslav сказал:

Запросить менеджер сенсоров System.Sensors.TSensorManager.Current;

Обнаружил нюанс: если обращаться к TSensorManager.Current из события POSIX таймера, монитор выдает такую ошибку:

E/error(19014): - Сan't start sensor: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

А что это за лупер, и почему его нет в моем потоке, я пока ни как не могу разобраться.

Ссылка на комментарий
  • 0
  • Администраторы
19 часов назад, Pax Beach сказал:

А что это за лупер, и почему его нет в моем потоке, я пока ни как не могу разобраться.

Эта реализация с Posix таймерами работает в отдельном треде. Который никак не связан с джава и андроидом. Поэтому, если вы хотите работать с сенсорами, вам достаточно синхронизировать вызов с главным тредом.

Ссылка на комментарий
  • 0
1 минуту назад, Brovin Yaroslav сказал:

Эта реализация с Posix таймерами работает в отдельном треде. Который никак не связан с джава и андроидом. Поэтому, если вы хотите работать с сенсорами, вам достаточно синхронизировать вызов с главным тредом.

Спасибо, Ярослав.

Есть вопросы: какой вызов нужно синхронизировать с главным потоком и как это делается в Delphi?

Сложный для моего понимания вопрос. Ни как не могу понять, как синхронизация позволяет передать в поток таймера контекст основного потока. Наверное, потому что кусками материал изучаю. Вот если бы пример на Java или, еще лучше, Delphi.

 

Ссылка на комментарий
  • 0
  • Модераторы

если брать реализацию для андроида, то есть решение без сенсора в этой  теме

там в первом сообщении, вложение

Ссылка на комментарий
  • 0
  • Администраторы
  1. TThread.Synchronize;
  2. Вызывать из кода обработчика таймера
  3. Чтобы понять, как это происходит, нужно почитать о том, как работает UI Thread (например тут). В этой статье, как раз рассказывает, что такое лупер и как организуется "якобы многозадачность" (отрисовка, обработка событий и тд) в рамках одного треда.
  4. Синхронизация не передает контекст. В данном случае контекст привязан к потоку. Он является частью потока. Поэтому по сути, когда вы синхронизируете (по сути просто вызываете ваш код из лупера, то по сути вы уже работаете в контексте :-)

Если заглянуть в исходники андроида:

public final class Looper {
// Вырезан код
  
      public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            msg.target.dispatchMessage(msg);

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }

            msg.recycleUnchecked();
        }
    }
///------------------------------
}

То есть по сути это просто бесконечный цикл, в котором из очереди вытаскиваются задания и выполняются по очереди. Как только возникает событие, оно просто складывается в очередь, и лупер в UI треде его просто обрабатывает. Когда вы вызываете TThread.Synchronize, то в конечном итоге ваш код завернется в сообщение, которое будет вызвано из этого куска кода

Ссылка на комментарий
  • 0
31 минуту назад, ZuBy сказал:

если брать реализацию для андроида, то есть решение без сенсора в этой  теме

там в первом сообщении, вложение

Спасибо, актуально.

Но мои устройства работают без интернета, sim-карт и Wi-Fi, только GPS в сервисе.

Соответственно, работать могу только с сенсором.

 

Ссылка на комментарий
  • 0
В 29.06.2016 в 12:00, Brovin Yaroslav сказал:
  • TThread.Synchronize;
  • Вызывать из кода обработчика таймера

 

Попробовал синхронизацию — сервис зависает на вызове TThread.Synchronize. 

TJLocalBroadcastManager решил проблему, код ниже.

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

Помогите пожалуйста понять, как уничтожить анонимный поток, когда завершаться сервис (или приложение)?

procedure TSvcMain.AndroidServiceCreate(Sender: TObject);
var
  LThread: TThread;
begin
  MyService := JavaService; // глобальная переменная
  FThreads := TObjectList<TThread>.Create;

  RegisterReceiver;

  StartLocationSensor;

  LThread := TThread.CreateAnonymousThread(
    procedure
    begin
      Log('+ Thread [%d] started', [TThread.CurrentThread.ThreadID]);
      while TThread.CurrentThread.Started do
      begin
        Log('... Thread [%d] ticked', [TThread.CurrentThread.ThreadID]);
        Sleep(TimerInterval);
        if (not Assigned(MyService)) or (not TThread.CurrentThread.Started) then
        begin
          Log('- stop Thread [%d]', [TThread.CurrentThread.ThreadID]);
          break;
        end
        else
        begin
          TJLocalBroadcastManager.JavaClass.getInstance(MyService)
           .sendBroadcast(TJIntent.JavaClass.init(StringToJString(LocationAction)));
        end;
      end;
      TThread.CurrentThread.Terminate;
    end);
  LThread.FreeOnTerminate := false;
  FThreads.Add(LThread);
  LThread.Start;
end;

При уничтожении сервиса я пытаюсь убить поток:

procedure TSvcMain.AndroidServiceDestroy(Sender: TObject);
var
  i: Integer;
begin
  StopLocationSensor;

  try
    for i := 0 to FThreads.Count - 1 do
      if Assigned(FThreads.Items[i]) then
      begin
        Log('Thread [%d] terminated', [FThreads.Items[i].ThreadID]);
        FThreads.Items[i].Terminate;
      end;
  finally
    FThreads.Free;
  end;
end;

 

Изменено пользователем Pax Beach
Ссылка на комментарий

Присоединяйтесь к обсуждению

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

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...