• 0
Rusland

Таймер в сервисе

Вопросы

Обычный TTimer использовать нельзя. Кстати почему нельзя? Почему он обращается к Активити в Androidapi.Helpers?

Embarcadero исправьте уже свой баг.

 

Как реализовать timer в сервисе?

Изменено пользователем Rusland

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

24 ответа на этот вопрос

  • 0

Можно в сервисе создать отдельный поток, а в нем:

 

while not Terminated do
begin
   // что то делаем 
       sleep (1000); // пауза 1 сек
end;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Когда-то, лет 5 назад у меня возникла такая-же проблема, только в Win32-сервисе. Тогда, для её решения, я написал 2 простеньких класса.

Вот код, может пригодится?

unit Utils.TimerThread;

interface

uses
  System.Classes, System.SysUtils, System.SyncObjs;


type
  TCustomTimerThread = class abstract (TThread)
  private
    FLock: TCriticalSection;
    FCancelledEvent: TSimpleEvent;

    FInterval: Integer;
    FOnTimer: TNotifyEvent;

    function GetInterval: Integer;
    function GetOnTimer: TNotifyEvent;
    procedure SetInterval(const Value: Integer);
    procedure SetOnTimer(const Value: TNotifyEvent);
  protected
    procedure Lock;
    procedure Unlock;

    procedure Sleep(AInterval: Integer); reintroduce;
    procedure TerminatedSet; override;

    procedure DoOnTimer; virtual;
  public
    constructor Create(AInterval: Integer; AOnTimer: TNotifyEvent); reintroduce;
    procedure BeforeDestruction; override;
    procedure Cancel; virtual;

    property Interval: Integer read GetInterval write SetInterval;
    ///	<summary>
    ///   <para>
    ///	    За синхронизацией потоков отвечает поток в котором обрабатывается OnTimer
    ///   </para>
    ///   <para>
    ///	    !!! НЕ ЗАБЫВАТЬ ПРО ЭТО !!!
    ///   </para>
    ///	</summary>
    property OnTimer: TNotifyEvent read GetOnTimer write SetOnTimer;
  end;

  ///	<summary>
  ///	  Simple wait thread
  ///	</summary>
  ///	<remarks>
  ///	  <para>
  ///	    !!! Important !!!
  ///	  </para>
  ///	  <para>
  ///	    Use Cancel instead of Terminate. You can get ThreadExternalTerminate
  ///	    exception in multi-thread applications
  ///	  </para>
  ///	</remarks>
  TWaitThread = class(TCustomTimerThread)
  protected
    procedure Execute; override;
  public
  end;

  ///	<summary>
  ///	  Thread independed timer
  ///	</summary>
  ///	<remarks>
  ///	  <para>
  ///	    !!! Important !!!
  ///	  </para>
  ///	  <para>
  ///	    Use Cancel instead of Terminate. You can get ThreadExternalTerminate
  ///	    exception in multi-thread applications
  ///	  </para>
  ///	</remarks>
  TTimerThread = class(TCustomTimerThread)
  private
    FEnabled: Boolean;

    function GetEnabled: Boolean;
    procedure SetEnabled(const Value: Boolean);
  protected
    procedure Execute; override;
  public
    constructor Create(AInterval: Integer; AOnTimer: TNotifyEvent; AEnabled: Boolean = True); reintroduce;
    property Enabled: Boolean read GetEnabled write SetEnabled;

  end;

implementation

{ TCustomTimerThread }

procedure TCustomTimerThread.BeforeDestruction;
begin
  FLock.Free;
  FreeAndNil(FCancelledEvent);

  inherited;
end;

constructor TCustomTimerThread.Create(AInterval: Integer; AOnTimer: TNotifyEvent);
begin
  inherited Create;

  FInterval := AInterval;
  FOnTimer := AOnTimer;

  FreeOnTerminate := True;

  FLock := TCriticalSection.Create;
  FCancelledEvent := TSimpleEvent.Create;
  FCancelledEvent.ResetEvent;
end;

procedure TCustomTimerThread.Cancel;
begin
  FCancelledEvent.SetEvent;
end;

procedure TCustomTimerThread.DoOnTimer;
begin
  if Assigned(OnTimer) then
    OnTimer(Self);
end;

function TCustomTimerThread.GetInterval: Integer;
begin
  Lock;
  try
    Result := FInterval;
  finally
    Unlock;
  end;
end;

function TCustomTimerThread.GetOnTimer: TNotifyEvent;
begin
  Lock;
  try
    Result := FOnTimer;
  finally
    Unlock;
  end;
end;

procedure TCustomTimerThread.Lock;
begin
  FLock.Enter;
end;

procedure TCustomTimerThread.SetInterval(const Value: Integer);
begin
  Lock;
  try
    FInterval := Value;
  finally
    Unlock;
  end;
end;

procedure TCustomTimerThread.SetOnTimer(const Value: TNotifyEvent);
begin
  Lock;
  try
    FOnTimer := Value;
  finally
    Unlock;
  end;
end;

procedure TCustomTimerThread.Sleep(AInterval: Integer);
begin
  FCancelledEvent.WaitFor(AInterval);
end;

procedure TCustomTimerThread.TerminatedSet;
begin
  inherited;

  FCancelledEvent.SetEvent;
end;

procedure TCustomTimerThread.Unlock;
begin
  FLock.Leave;
end;

{ TWaitThread }

procedure TWaitThread.Execute;
begin
  if FCancelledEvent.WaitFor(FInterval) = wrTimeout then
    DoOnTimer;
end;

{ TTimerThread }

constructor TTimerThread.Create(AInterval: Integer; AOnTimer: TNotifyEvent; AEnabled: Boolean);
begin
  inherited Create(AInterval, AOnTimer);

  FOnTimer := AOnTimer;
  FEnabled := AEnabled;
end;

procedure TTimerThread.Execute;
begin
  while not Terminated do
    case FCancelledEvent.WaitFor(FInterval) of
      wrTimeout:
        begin
          if Enabled then
            DoOnTimer;
        end;
      else
        Break;
    end;
end;

function TTimerThread.GetEnabled: Boolean;
begin
  Lock;
  try
    Result := FEnabled;
  finally
    Unlock;
  end;
end;

procedure TTimerThread.SetEnabled(const Value: Boolean);
begin
  Lock;
  try
    FEnabled := Value;
  finally
    Unlock;
  end;
end;

end.

 

Изменено пользователем dnekrasov
Исправлен исходник

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
10 часов назад, dnekrasov сказал:

Вот код, может пригодится?

Спасибо большое, хороший полезный класс!

Можно еще выложить простой пример использования — создание, инициализация, запуск, остановка, уничтожение? Думаю, очень поможет форумчанам.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

В архиве - простенький проект. Протестирован на Win и OSX.

 

TimerThreadDemo.zip

Изменено пользователем dnekrasov
Заменен архив - отсутствовал один файл

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
57 минут назад, dnekrasov сказал:

В архиве - простенький проект. Протестирован на Win и OSX.

TimerThreadDemo.zip

Допилим, если не будет работать. Спасибо!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
11 минуту назад, Pax Beach сказал:

Допилим, если не будет работать

Не забудьте поделиться :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

dnekrasov, не удалось понять, как правильно запустить таймер в сервисе.

Ваш модуль хорошо работает в обычном приложении, но в сервисе не срабатывает событие таймера. Ни WaitComplete, ни TimerThreadOnTimer. Кстати в приведенном Вами примере нет формы, только модуль.

Приведу код моего сервиса, и лог, может кто-нибудь поймет в чем дело. Сервис нормально работает и вручную (по событию остановки сервиса) нормально выключается.

unit Unit1;

interface

uses
  System.SysUtils,
  System.Classes,
  System.Android.Service,
  AndroidApi.JNI.GraphicsContentViewText,
  AndroidApi.JNI.Os,
  System.IOUtils,
  Utils.TimerThread,
  AndroidApi.JNI.App, // TJService.JavaClass.START_STICKY
  AndroidApi.Log,
  AndroidApi.JNI.JavaTypes, // JString
  AndroidApi.Helpers; // StringToJString

const
{$IF DEFINED(ANDROID) OR DEFINED(IOS)}
  AUDIO_FILENAME = 'test.caf';
{$ELSE}
  AUDIO_FILENAME = 'test.wav';
{$ENDIF}

Const
  RecordTime = 3000;

type
  TDM = class(TAndroidService)
    function AndroidServiceStartCommand(const Sender: TObject; const Intent: JIntent;
      Flags, StartId: Integer): Integer;
    function AndroidServiceHandleMessage(const Sender: TObject; const AMessage: JMessage): Boolean;
    function AndroidServiceBind(const Sender: TObject; const AnIntent: JIntent): JIBinder;
    procedure AndroidServiceTaskRemoved(const Sender: TObject; const ARootIntent: JIntent);
  private
    FTimer: TTimerThread;

    procedure WaitComplete(Sender: TObject);
    procedure TimerThreadStart;
    procedure TimerThreadStop;
    procedure TimerThreadOnTimer(Sender: TObject);
  public
    { Public declarations }
  end;

var
  DM: TDM;

implementation

{ %CLASSGROUP 'FMX.Controls.TControl' }

{$R *.dfm}

procedure Log(const Fmt: string; const Params: array of const);
var
  Msg: string;
  M: TMarshaller;
begin
  Msg := Format(Fmt, Params);
  LOGI(M.AsUtf8(Msg).ToPointer);
end;

function TDM.AndroidServiceBind(const Sender: TObject; const AnIntent: JIntent): JIBinder;
begin
  Log('+ BIND: ' + JStringToString(AnIntent.getAction.toString) + ' - ' +
    JStringToString(AnIntent.getData.toString), []);
end;

function TDM.AndroidServiceHandleMessage(const Sender: TObject; const AMessage: JMessage): Boolean;
begin
  Log('+ MESSAGE: ' + JStringToString(AMessage.toString) + ' - ' +
    JStringToString(AMessage.getData.toString), []);
  Result := True;
end;

function TDM.AndroidServiceStartCommand(const Sender: TObject; const Intent: JIntent;
  Flags, StartId: Integer): Integer;
begin
  Log('+ START: ' + JStringToString(Intent.getAction.toString), []);
  if Intent.getAction.equalsIgnoreCase(StringToJString('StopIntent')) then
  begin
    Log('...Service stoped', []);
    TimerThreadStop;
    JavaService.stopSelf;
    Result := TJService.JavaClass.START_NOT_STICKY;
  end
  else
  begin
    Log('...Service started', []);
    TimerThreadStart;
    Result := TJService.JavaClass.START_STICKY;
  end;
end;

procedure TDM.AndroidServiceTaskRemoved(const Sender: TObject; const ARootIntent: JIntent);
begin
  Log('- TASK REM: ' + JStringToString(ARootIntent.getAction.toString), []);
end;

procedure TDM.TimerThreadOnTimer(Sender: TObject);
begin
  TThread.Synchronize(TThread(Sender),
    procedure
    begin
      Log('+++ Timer worked.', []);
      TimerThreadStop;
    end);
end;

procedure TDM.TimerThreadStart;
begin
  if not Assigned(FTimer) then
    FTimer := TTimerThread.Create(RecordTime, TimerThreadOnTimer)
  else
    FTimer.Interval := RecordTime;

  FTimer.Enabled := True;

  Log('+ Timer started', []);
end;

procedure TDM.TimerThreadStop;
begin
  if not Assigned(FTimer) or not FTimer.Enabled then
  begin
    Log('- Timer not enabled', []);
    Exit
  end
  else
  begin
    FTimer.Enabled := False;
    FTimer.Cancel;
  end;
  Log('- Timer stoped', []);
end;

procedure TDM.WaitComplete(Sender: TObject);
begin
  TThread.Synchronize(TThread(Sender),
    procedure
    var
      Msg: string;
      M: TMarshaller;
    begin
      Log('- WaitComplete', []);

      JavaService.stopSelf;

      Log('Service stoped', []);
    end);
end;

end.

«FMX: Project1:»  — это мой хост, который запускает сервис. Остальное выдает сервис.

Что я сделал? — Запустил хост на HTC One, отправил Intent «StartIntent», сервис запустился, поток запустился. Подождал несколько секунд, отправил Intent «StopIntent», поток остановился, сервис остановился.

Далее лог: 

05-31 23:38:29.709: I/info(17885): FMX: Project1: Try to start
05-31 23:38:29.712: W/linker(17885): /data/app/com.embarcadero.Project1-1/lib/arm/libProject2.so: is missing DT_SONAME will use basename as a replacement: "libProject2.so"
05-31 23:38:29.985: I/info(17885): + START: StartIntent
05-31 23:38:29.985: I/info(17885): ...Service started
05-31 23:38:29.985: I/info(17885): + Timer started
05-31 23:38:41.754: I/info(17885): FMX: Project1: Try to stop
05-31 23:38:41.755: I/info(17885): + START: StopIntent
05-31 23:38:41.755: I/info(17885): ...Service stoped
05-31 23:38:41.755: I/info(17885): - Timer stoped

 

Изменено пользователем Pax Beach

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Старт таймера с 0 интервалом происходит?

if not Assigned(FTimer) then
  FTimer := TTimerThread.Create(RecordTime, TimerThreadOnTimer);
FTimer.Interval := RecordTime;

UPDATE: не заметил, что в конструкторе интервал как параметр

Изменено пользователем ZuBy

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Посмотрите на реализацию системных таймеров в Androidapi.Timer.pas. Они подходят для сервисов.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
10 часов назад, Brovin Yaroslav сказал:

Посмотрите на реализацию системных таймеров в Androidapi.Timer.pas. Они подходят для сервисов.

Спасибо за подсказку.

Что-то я не пойму, как с этим модулем правильно работать.

Таймер нужно запускать через TTimerManager из FMX.Platform.Android.pas или AndroidTimerCreate->AndroidTimerSetInterval->AndroidTimerSetHandler?

Примеров и документации нигде нет. Опять на 4 часа завис с кодом =(

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
function AndroidTimerCreate: Integer;

Создает таймер и возвращает его идентификатор

procedure AndroidTimerSetInterval(TimerHandle: Integer; Interval: Integer);

Задает для созданного таймера по его ID интервал срабатывания.

Эта реализация работает с одним обработчиком OnTimer для всех таймеров. Чтобы задать такой общий обработчик используется процедура:

procedure AndroidTimerSetHandler(OnTimer: TAndroidTimerNotify);

В параметре OnTimer приходит ваш идентификатор таймера.

procedure AndroidTimerDestroy(TimerHandle: Integer);

Этот метод уничтожает созданный вами таймер по ID

Этот юнит - это оболочка над posix-таймерами

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Brovin Yaroslav, заработал мой сервис с этим модулем, спасибо!

Но... при уничтожении таймера умирает сервис и хост, вылетают с ошибкой «Native thread exiting without having called DetachCurrentThread (maybe it's going to use a pthread_key_create destructor?)» (ниже в логе).

Видимо нужно для таймера сначала нужно как-то выполнить DetachCurrentThread. Не понимаю только — Как?

Коллеги, посоветуете, что можно сделать с отключением таймера?

Так я запускаю таймер:

procedure TDM.StartTimer;
begin
  Log('... timer to be started', []);
  FTimerHandle := AndroidTimerCreate;
  FTimerCounter := 0;
  AndroidTimerSetInterval(FTimerHandle, TimerInterval);

  AndroidTimerSetHandler(WaitComplete);
  Log('+ Timer started', []);
end;

Так я останавливаю таймер. После выполнения таймера, сервис мне не нужен тоже, останавливаю.

procedure TDM.StopTimer;
begin
  StopRecord;

  if FTimerHandle > 0 then
  begin
    Log('... timer to be stoped', []);
    AndroidTimerSetHandler(nil);
    Log('... timer to be destroyed', []);
    AndroidTimerDestroy(FTimerHandle); // ТУТ УМИРАЕТ СЕРВИС И ХОСТ-ПРИЛОЖЕНИЕ !!!
    FTimerHandle := 0;
    Log('- Timer stoped', []);
  end;

  Log('... Service to be stoped', []);
  JavaService.stopSelf;
end;

Вот так я работаю с запуском и остановкой сервиса:

function TDM.AndroidServiceStartCommand(const Sender: TObject; const Intent: JIntent;
  Flags, StartId: Integer): Integer;
begin
  Log('+ START with Intent: ' + JStringToString(Intent.getAction.toString), []);
  if Intent.getAction.equalsIgnoreCase(StringToJString('StopIntent')) then
  begin
    StopRecord;

    StopTimer;

    Log('...Service to be stoped', []);
    JavaService.stopSelf;

    Result := TJService.JavaClass.START_NOT_STICKY; // don't reload service
  end
  else
  begin
    Log('... service started', []);

    if not IsMicrophoneRecording then
    begin
      Log('... sound record to be started', []);
      StartRecord;
    end;

    StartTimer;

    Result := TJService.JavaClass.START_STICKY; // rerun service if it stops
  end;
end;

 

А вот лог, где последние две строки — ошибка, при попытке уничтожить таймер:

06-02 16:57:50.460: W/linker(17598): /data/app/com.embarcadero.ProjectAppRec-1/lib/arm/libProjectAppRec.so: is missing DT_SONAME will use basename as a replacement: "libProjectAppRec.so"
06-02 16:57:51.679: I/Adreno-EGL(17598): <qeglDrvAPI_eglInitialize:379>: EGL 1.4 QUALCOMM build: Nondeterministic_AU_msm8974_LA.BF.1.1.3__release_AU (I3fa967cfef)
06-02 16:57:51.679: I/Adreno-EGL(17598): OpenGL ES Shader Compiler Version: E031.28.00.02
06-02 16:57:51.679: I/Adreno-EGL(17598): Build Date: 09/29/15 Tue
06-02 16:57:51.679: I/Adreno-EGL(17598): Local Branch: mybranch14683032
06-02 16:57:51.679: I/Adreno-EGL(17598): Remote Branch: quic/master
06-02 16:57:51.679: I/Adreno-EGL(17598): Local Patches: NONE
06-02 16:57:51.679: I/Adreno-EGL(17598): Reconstruct Branch: NOTHING
06-02 16:58:32.859: I/info(17598): FMX: ProjectAppRec: Try to start
06-02 16:58:32.880: W/linker(17598): /data/app/com.embarcadero.ProjectAppRec-1/lib/arm/libProxyAndroidService.so: is missing DT_SONAME will use basename as a replacement: "libProxyAndroidService.so"
06-02 16:58:32.905: W/linker(17598): /data/app/com.embarcadero.ProjectAppRec-1/lib/arm/libSvcTimer.so: is missing DT_SONAME will use basename as a replacement: "libSvcTimer.so"
06-02 16:58:33.237: I/info(17598): + START with Intent: StartIntent
06-02 16:58:33.237: I/info(17598): ... service started
06-02 16:58:33.237: I/info(17598): ... timer to be started
06-02 16:58:33.237: I/info(17598): + Timer started
06-02 16:58:34.240: I/info(17598): +++ Timer is triggered  time.
06-02 16:58:35.238: I/info(17598): +++ Timer is triggered  time.
06-02 16:58:36.238: I/info(17598): +++ Timer is triggered  time.
06-02 16:58:37.239: I/info(17598): +++ Timer is triggered  time.
06-02 16:58:38.239: I/info(17598): +++ Timer is triggered  time.
06-02 16:58:39.239: I/info(17598): +++ Timer is triggered  time.
06-02 16:58:40.239: I/info(17598): +++ Timer is triggered  time.
06-02 16:58:41.239: I/info(17598): +++ Timer is triggered  time.
06-02 16:58:42.239: I/info(17598): +++ Timer is triggered  time.
06-02 16:58:43.239: I/info(17598): +++ Timer is triggered  time.
06-02 16:58:44.237: I/info(17598): ... timer to be stoped
06-02 16:58:44.237: I/info(17598): ... timer to be destroyed
06-02 16:58:44.237: I/info(17598): - Timer stoped
06-02 16:58:44.237: I/info(17598): ... Service to be stoped
06-02 16:58:44.239: W/art(17598): Native thread exiting without having called DetachCurrentThread (maybe it's going to use a pthread_key_create destructor?): Thread[12,tid=17927,Native,Thread*=0xba7bbb50,peer=0x12d34100,"Thread-42654"]
06-02 16:58:44.239: A/art(17598): art/runtime/thread.cc:1228] Native thread exited without calling DetachCurrentThread: Thread[12,tid=17927,Native,Thread*=0xba7bbb50,peer=0x12d34100,"Thread-42654"]

 

Изменено пользователем Pax Beach
внесены уточнения вопроса

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Это не хорошее решение, а костыль, но пока решает мою задачу:

Когда нужное мне событие произошло, я просто убираю обработчик таймера

AndroidTimerSetHandler(nil);

А когда нужен таймер, снова назначаю обработчик:

AndroidTimerSetHandler(WaitComplete);

При этом таймер продолжает работать и занимать процесс, когда он фактически не нужен — это, конечно же, не хорошо.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

А можно поподробнее! Необходимо что бы через каждые 10 сек выполнялась функция "Функция"

Создаю таймер

TimerID :=  AndroidTimerCreate;
AndroidTimerSetInterval(TimerID,10000);

Назначаю обработчик  вылетает ошибка
 

  AndroidTimerSetHandler("Функция");

как правильно назначить обработчик на нужную функцию

Изменено пользователем cherezovmax

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
1 час назад, cherezovmax сказал:

А можно поподробнее! Необходимо что бы через каждые 10 сек выполнялась функция "Функция"

Создаю таймер


TimerID :=  AndroidTimerCreate;
AndroidTimerSetInterval(TimerID,10000);

Назначаю обработчик  вылетает ошибка
 


  AndroidTimerSetHandler("Функция");

как правильно назначить обработчик на нужную функцию

Вот пример, в котором реализованы ваши задачи.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

cherezovmax

uses
  AndroidApi.Log,            // LOGI
  Androidapi.Timer,
...
  private
    { Private declarations }
    FTimerHandle: integer;
    FTimerCounter: integer;
    TimerInterval: integer;
    procedure StartTimer;
    procedure WaitComplete(TimerId: Integer);

...
procedure TDM.AndroidServiceCreate(Sender: TObject);
begin
  FTimerHandle := AndroidTimerCreate;
  FTimerCounter := 0;
  TimerInterval:=5000;
end;

function TDM.AndroidServiceStartCommand(const Sender: TObject;
  const Intent: JIntent; Flags, StartId: Integer): Integer;
begin
  StartTimer;
  LogI('TJService.JavaClass.START_STICKY');
  Result := TJService.JavaClass.START_STICKY;
end;

procedure TDM.StartTimer;
begin
  LogI('... timer to be started');
  AndroidTimerSetInterval(FTimerHandle, TimerInterval);
  AndroidTimerSetHandler(WaitComplete);
  LogI('+ Timer started');
end;


procedure TDM.WaitComplete(TimerId: Integer);
begin
  LogI('WaitComplete procedure')
end;

 

Изменено пользователем Rusland

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Подскажите, куда здесь влепить свою функцию?) 

В 21.09.2016 в 12:46, Rusland сказал:

procedure TDM.WaitComplete(TimerId: Integer);
begin
  LogI('WaitComplete procedure')
end;

В WaitComplete правильно понимаю? И как можно из своей функции стартовать таймер и отключать его при прохождении интервала? :/

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
1 час назад, MikeWuzHere сказал:

Подскажите, куда здесь влепить свою функцию?) 

В WaitComplete правильно понимаю? И как можно из своей функции стартовать таймер и отключать его при прохождении интервала? :/

Так есть же пример выше

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

имхо, я бы на старте службы запустил цикл со Sleep(10) и проверял сколько прошло времени вот этим кодом:

class MyTimer
{
private:
	clock_t startTicks;
	double coef;
public:
	MyTimer(){ coef = 1000.0f / CLOCKS_PER_SEC; }
	void Start() { startTicks = clock(); }
	float GetTimeSec(){ return ( clock() - startTicks ) * coef / 1000.0f; }
	float GetTimeMSec(){ return ( clock() - startTicks ) * coef; }
};

работает на винде и андроид, что-то типа:

MyTimer Timer;
Timer.Start();
while(true)
	{
		if ( flag_exit ) break;
		if ( Timer.GetTimeSec() < 15 )
        	{
              // что-то делаем в режиме ожидания
              Sleep(10);
            }
		// что-то делаем по таймеру	
        Timer.Start();                      
	}

код на си, но все функции есть в объект-паскале, думаю алгоритм понятен

хотя не факт что #include <time.h> есть в дельфи, а в билдере нет служб андроид, хаха

Изменено пользователем Камышев Александр

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

нету clock() в Delphi, сишный эксклюзив, только GetTickCount в TThread...

с другой стороны зачем такая точность, clock() возвращает тики процессора, тут достаточно системное время запросить

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти

  • Похожий контент

    • От x11
      Это не вопрос. Просто подумал, что кому-нибудь может пригодится.
      https://forums.embarcadero.com/thread.jspa?threadID=118465
      Используем 2 файла: Androidapi.JNI.ToastForService.pas + FlyUtils.Android.PostRunnableAndTimer.pas.
      Пример вызова:
      Androidapi.JNI.ToastForService.PostToast('текст сообщения', LongToast); Проверил - работает.
      Есть ещё третий параметр "UseLastToastObj", но я так и не понял, для чего он. Документации нет.
    • От x11
      Приложение + служба.
      В службе установлен флаг перезапуска в StrartCommand^
      result := TJService.JavaClass.START_STICKY; // rerun service if host app stops  
      Проблема вот в чем. На экране главная форма хост-приложения.  На смартфоне внизу нажимаю кнопку Назад. Приложение закрывается.
      Вижу в LogCat Андроида, что аварийно завершается служба. Андроид восстанавливает работу службы и запускает и службу и само приложение. Хотя Андроид не должен перезапускать host-приложение, а только службу.
       
       
      Т.е. вижу, что поле выхода приложение со службой работают.
      Когда с рабочего стала ланчера запсукаю host-приложение, то оно виснет при старте и даже событие OnCreate главной формы не срабатывает. Показывается стартовое окно (splash) и висит, пока Андроид не предложит закрыть или подождать. И так несколько раз приходится делать, пока приложение не запустится.
      Я в OnClose главной формы разные параметры прописывал для action, но толку нет.
      Хоть какой-нибудь костыль посоветуйте, пожалуйста.
       
      А когда нажимаю кнопку Домой на смартфоне, то приложение сворачивается и тогда запсу с рабочего стола ланчера происходит нормально, т.е. приложение просто всплывает.
      Может можно как-то при закрытии приложения не закрывать его, а сворачивать?
      Если я не запускаю службу, то приложение закрывается и потом запускается нормально с рабочего стола ланчера.
      Заранее благодарен.
    • От brunnengi
      Здравствуйте.
      Требуется программа на андроид с набором кнопок со следующем функционалом:
      1. Кнопка1 - создать базу в test.sqlite (в том месте где доступ к нему есть только у самого приложения (имею ввиду если это не ROOT телефон, при рут и так всё понятно)
      2. Кнопка2 - создать таблицу в базе test.sqlite с названием "TblTest01" (с разным набором полей на своё усмотрение)
      3. Кнопка3 - создать таблицу в базе test.sqlite с названием "TblTest02" (с разным набором полей на своё усмотрение)
      4. Кнопка4 - Добавить строку в таблицу "TblTest01" (любой набор данных на ваших усмотрение)
      5. Кнопка5 - Удалить строку в таблице "TblTest01" (по любому ключу на ваше усмотрение)
      6. Кнопка6 - Изменить строку в таблице "TblTest01" (по любому ключу и любое значение на ваше усмотрение)
       
      Приложение должно иметь фоновый сервис, который должен получать данные с сервера и добавлять их в базу test.sqlite в таблицу "TblTest02".
      При получение новый данных, сервис должен показать в "шторке" сообщение, по клику на которую открывается само приложение с визуальной частью.
      Т.е. если визуально приложение закрыто, выгружено, не запущено или запущено, фоновый процесс должен сам делать запросы к серверу и добавлять новые данные в базу, если они есть/поступили
      Приложение должно запускаться вместе с системой, после перезагрузки и т.д.
      Использовать только те компоненты что доступны в самой среде из коробки.
      Часть где делается запрос к серверу должен иметь timeout равный 20 секундам.
      Сервис должен грамотно делать запросы к серверу как положено в Андроид приложениях. 
      Серверная часть мне не нужна, можете для теста сами эмулирвать эти процессы.
       
       
      -----
      ЦЕНА: 2500р.
      СРОКИ: Не горит, но в целом где то дней 7 есть
      Перечисляю на QIWI, ЯД, Сбербанк, короче куда скажите.
    • От x11
      Как проверить, работает ли моя служба?
      Т.е. перед запуском или остановкой хочется выполнить проверку.
       
      FService := TJIntent.Create; FService.setClassName(TAndroidHelper.Context.getPackageName, TAndroidHelper.StringToJString('com.embarcadero.services.pak1')); FService.setAction(StringToJString('StopService')); TAndroidHelper.Activity.startService(FService);  
    • От x11
      На основе нескольких тем форума сделал службу перехвата звонков и номера телефона.
      http://fire-monkey.ru/topic/3878-статьякак-создать-простой-android-broadcast-receiver-how-to-implement-simplest-android-broadcast-receiver-in-delphi/
      http://fire-monkey.ru/topic/2386-перехват-события-звонка/
      http://fire-monkey.ru/topic/2972-использование-нативных-localbroadcastmanager-и-broadcastreceiver/
      Покритикуйте пожалуйста. Уверен, что не всё правильно.
      Но что до ума не удалось довести, так это то, как правильно останавливать службу и закрывать приложение.
      Проект (для Токио) приложил теме.
      Заранее благодарен.
       
      BR2.rar
    • От x11
      Заметил, что после удаления библиотеки-сервиса всё равно в host-приложении остаётся мусор.

    • От x11
      Прошу помощи или хотя бы совета.
      Кто-то уже пытался создать службу, которая может перехватывать звонки входящие и исходящие?
      Пример для обычного приложения есть с таким кодом
      TPlatformServices.Current.SupportsPlatformService(IFMXPhoneDialerService, IInterface(PhoneDialerService)); if Assigned(PhoneDialerService) then PhoneDialerService.OnCallStateChanged := MyOnCallStateChanged;  
      Плюс пытаюсь всё это скрестить с NotificationCenter, но служба при запуске зависает и падает.
       
       
    • От x11
      Экспериментировал с сервисами.
      После переименования проекта библиотеки сервиса удалил и снова хочу добавить к host-проекту библиотеку-service.
      На первом шаге выбираю "Искать автоматически". На втором выбираю папку, где живет проект-библиотека, но среда ругается и выдает старое имя. Но я не могу найти, где именно среда находит это старое имя.


    • От x11
      Использую стандартный пример из папки
      C:\Users\Public\Documents\Embarcadero\Studio\19.0\Samples\Object Pascal\Multi-Device Samples\Device Sensors and Services\AndroidNotificationServiceDemo\NotificationService
      Delphi Tokyo.
      Компилируется и запускается на устройстве. Нажимаю кнопку Start service, но ничего не происходит. Т.е. совсем ничего: ни ошибок, ни падений приложения, никаких сообщений.
      В какую строну копать?
      И вообще, как проверить, работает ли мой сервис?
       
      Я от крыл в настройках андроида "Запущенные программы", но там нет даже моего приложения в списке, хотя приложение запущено.
      Пробовал на Андроид версий 5 и 6.
  • Последние посетители   0 пользователей онлайн

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