Перейти к содержанию

Вопросы

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

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

 

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

Отредактировал Rusland

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


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

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

  • 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() возвращает тики процессора, тут достаточно системное время запросить

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


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

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

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

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

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

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

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

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

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


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

    • От Евгений Корепов
      Я написал класс для демонизации приложения в linux. Класс форкает процесс, обрабатывает поступающие сигналы и передает их в основной поток через потокобезопасную очередь.
      Исходники https://github.com/EvgeniyKorepov/LinuxDaemon
      Для использования просто подключите модуль UnitDaemon в свое консольное приложение:
      program DaemonTest; {$APPTYPE CONSOLE} uses System.SysUtils, System.IOUtils, System.SyncObjs, Posix.Stdlib, Posix.SysStat, Posix.SysTypes, Posix.Unistd, Posix.Signal, Posix.Fcntl, Posix.Syslog in 'Posix.Syslog.pas', UnitDaemon in 'UnitDaemon.pas'; var AEventType : TEventType; begin syslog(LOG_NOTICE, 'main START'); while True do begin syslog(LOG_NOTICE, 'main LOOP'); if UnitDaemon.QueueEvent.PopItem(AEventType) = System.SyncObjs.TWaitResult.wrSignaled then begin syslog(LOG_NOTICE, 'main UnitDaemon.QueueEvent.PopItem'); case AEventType of TEventType.StopProcess : begin syslog(LOG_NOTICE, 'main Event StopProcess'); ExitCode := EXIT_SUCCESS; exit; end; TEventType.Start : begin syslog(LOG_NOTICE, 'main Event START'); end; TEventType.Reload : begin // Reload config syslog(LOG_NOTICE, 'main Event RELOAD'); end; TEventType.Stop : begin syslog(LOG_NOTICE, 'main Event STOP'); ExitCode := EXIT_SUCCESS; exit; end; end; end; Sleep(50); end; end. Так же поддерживается systemd - для этого положите  DaemonTest.service в /etc/systemd/system/ и используйте :
      systemctl start DaemonTest.service systemctl reload DaemonTest.service systemctl stop DaemonTest.service  
    • От Евгений Корепов
      Вот просто идеальная статья по запуску демона под Linux http://blog.paolorossi.net/2017/09/04/building-a-real-linux-daemon-with-delphi-part-2/ 
      Помимо объяснения механизма fork с отличными примерами,  есть куча дополнительной наиполезнейшей инфы.
    • От 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, но служба при запуске зависает и падает.
       
       
  • Последние посетители   0 пользователей онлайн

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

×
×
  • Создать...