Delphi 10 Seattle后台服务和线程 [英] Delphi 10 Seattle Background Service and Threads

查看:100
本文介绍了Delphi 10 Seattle后台服务和线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用Delphi 10 Seattle Update 1创建一个Android应用程序.

Using Delphi 10 Seattle Update 1 to create an Android application.

基本目标是让应用程序每隔几(4)小时弹出一次通知,以提醒用户起床和走动.

Basic goal is to have an application the pops up a notification every few (4) hours to remind the user to get up and move.

我已经创建了基本的UI并创建了后台服务.在该服务中,我可以使用TNotificationCenter很好地发布通知,但是我需要定期发布通知.

I have created the basic UI and created the background service. In the service I can use a TNotificationCenter to post a notification just fine, but I need to post a notification at a regular interval.

基于在以下站点上找到的建议...

Based on suggestions found at the following sites...

  • http://blog.blong.com/2015/02/delphi-and-android-services-part-3.html
  • http://blog.marcocantu.com/blog/2014_may_background_delphi_android_threads.html
  • embarcadero delphi XE10 android service with a timer
  • Also the AndroidNotificationServiceDemo that ships with the product...

我意识到我无法在Android Service中使用TTimer.我还尝试从AndroidServiceStartCommand和AndroidServiceCreate事件创建一个TTask,TThread.CreateAnonymousThread和一个老式的TThread后代.

I realized that I cannot use a TTimer in and Android Service. I have also tried to create a TTask, TThread.CreateAnonymousThread, and an old fashioned TThread descendant from both the AndroidServiceStartCommand and the AndroidServiceCreate event.

在sleep命令完成后,所有这些错误均引发相同的错误. "Project MoveProof.apk引发了异常类Segment错误(11)"

All of them throw the same error after the sleep command finishes. "Project MoveProof.apk raised exception class Segment fault (11)"

这是我现在正在使用的代码....

Here is the code I am using now....

unit UnitServiceMain;

interface

uses
    System.SysUtils
  , System.Classes
  , System.Android.Service
  , System.Notification

  , AndroidApi.JNI.GraphicsContentViewText
  , Androidapi.JNI.Os

  ;

type
  TServiceThread = class;

  TNotes = Array of String;

  TAndroidServiceDM = class(TAndroidService)
    NotificationCenterNotes: TNotificationCenter;
    function AndroidServiceStartCommand(const Sender: TObject; const Intent: JIntent; Flags, StartId: Integer): Integer;
    procedure AndroidServiceCreate(Sender: TObject);
    procedure AndroidServiceDestroy(Sender: TObject);
  private
    FNotes: TArray<string>;
    FThread: TServiceThread;
  public
    var Running: Boolean;

    Procedure LoadArray;
    Property Notes:TArray<string> read FNotes;
  end;

  TServiceThread = class(TThread)
  public
    Procedure Execute; override;
    Procedure DoNotification;
  end;

var
  AndroidServiceDM: TAndroidServiceDM;

implementation

{%CLASSGROUP 'FMX.Controls.TControl'}

{$R *.dfm}

Uses
    System.Threading
  , Androidapi.JNI.App
  ;

{ TServiceThread }

procedure TServiceThread.DoNotification;
Var
  NoteId: Integer;
  MyNotification: TNotification;
begin
  while (AndroidServiceDM <> nil) and AndroidServiceDM.Running do
    Begin
      try
        if (AndroidServiceDM <> nil) and AndroidServiceDM.Running then
          Begin
            AndroidServiceDM.NotificationCenterNotes.CancelAll;
            NoteID := Random(High(AndroidServiceDM.Notes));
            MyNotification := AndroidServiceDM.NotificationCenterNotes.CreateNotification;
            try
              MyNotification.Name := 'LoveNoteMessage'+InttoStr(NoteID);
              MyNotification.EnableSound := False;
              MyNotification.Number := NoteID;
              MyNotification.Title := 'Michael Said...';
              MyNotification.AlertBody := AndroidServiceDM.Notes[NoteID];
              AndroidServiceDM.NotificationCenterNotes.PresentNotification(MyNotification);
            finally
              MyNotification.DisposeOf;
            end;
          End;
      except
        on Exception do
          // Need to log this...
      end;
    end;
end;

procedure TServiceThread.Execute;
begin
  inherited;
  Sleep( 20000 );
  Synchronize(DoNotification);
end;

procedure TAndroidServiceDM.LoadArray;
begin
  if Length(FNotes) = 0 then
    Begin
      FNotes := TArray<string>.Create
      (
        'Get up and move.',
        'Time to keep moving.',
        'Lets take a walk.',
        'Move.'
      );
    End;
end;

procedure TAndroidServiceDM.AndroidServiceCreate(Sender: TObject);
begin
  Randomize;
  LoadArray;
end;

procedure TAndroidServiceDM.AndroidServiceDestroy(Sender: TObject);
begin
  FThread.Terminate;
  FThread := Nil;
end;

function TAndroidServiceDM.AndroidServiceStartCommand(const Sender: TObject; const Intent: JIntent; Flags, StartId: Integer): Integer;
begin
  JavaService.stopSelf;
  Result := TJService.JavaClass.START_STICKY;
  if not Running then
    begin
      Running := True;
      FThread := TServiceThread.Create(False);
    end;
end;


end.

我对线程没有经验,所以也许我在同步方面做错了.任何帮助将不胜感激.

I am not that experienced with threads, so maybe I am doing something wrong with synchronization. Any help would be appreciated.

推荐答案

无需将您的DoNotification放入线程中.只需在您的AndroidServiceCreate中设置一个带有永恒循环的TTask,然后检查经过的时间,然后在经过时调用DoNotification.

There's no need to put your DoNotification in a thread. Just setup a TTask with an eternal loop in your AndroidServiceCreate, and then check the elapsed time, and when it's passed, call the DoNotification then.

  T := TTask.Run (procedure
  begin
    TimeNow := Now;
    Count := 0;
    while true do
    begin
      sleep(20000);
      if SecondsBetween(TimeNow, Now) >= Floor(4 * 60 * 60) then
      begin
        DoNotification;
        TimeNow := Now;
      end;
    end;
  end);

您的通知看起来比需要的更为复杂,并且您在其中使用的不必要的循环可能是导致分段错误的原因.

Your notification looks more complicated than it needs to be, and the unnecessary loop you used there might be the cause of your segmentation fault.

  myNotification := NotificationCenter1.CreateNotification;
  try
    MyNotification.Name := 'ServiceNotification';
    MyNotification.Title := 'Android Service Notification';
    MyNotification.AlertBody := 'hello host, I'm your service'
    MyNotification.FireDate := Now;
    NotificationCenter1.PresentNotification(MyNotification); 
  finally
    myNotification.DisposeOf;
  end;

在Delphi中,Android服务的良好经验法则是编写最简单的代码即可完成工作,而无需其他任何操作.

The good rule of thumb for Android services in Delphi is to write the simplest code you can to get the job done and no more.

这篇关于Delphi 10 Seattle后台服务和线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆