Delphi XE10 Android服务GPS

4
我正在使用Emabarcadero Delphi XE 10 Seattle Update 1创建一个Android服务,我找到了这个教程链接并创建了一个服务应用程序,我想做的是使用位置传感器在每5秒获取当前位置并保存到数据库。我正在主窗体上实现,但当我关闭程序时它就停止了,所以我找不到任何关于如何同步我的应用程序和服务的文章。我尝试将定时器和位置传感器添加到服务表单中,但Delphi不允许我向服务表单添加任何对象,我认为我需要发送一个命令到服务或以某种方式连接服务和程序,我找到了一个示例,展示了如何使用服务下载图像,但对于像我这样的新手来说太高级了 :)

5
相关链接(针对Java):https://dev59.com/S2oy5IYBdhLWcg3wA5eC - mjn
除了服务外,您还需要AlarmManager来重复调用该服务。 - mjn
@mjn 感谢你提醒,我想我错过了那个,再次感谢。 - BMF
您的应用程序需要专家来开发完成。这不是一个“新手”的任务。 - Freddie Bell
此问题与链接中的问题不重复。 - nurettin
2个回答

1

请查看this文章。Daniele Spinetti使用服务中的LocationSensor解决问题。

将System.Sensors和System.Android.Sensors单元添加到您的项目中并进行更改(Delphi 10 Seattle)。

System.Sensors.pas

// about line 748
implementation
uses
  System.Variants, System.Math, System.Character,
{$IFDEF ANDROID}
  // -- patch 
  // include the modified System.Android.Sensors
  System.Android.Sensors;
{$ENDIF ANDROID}

System.Android.Sensors.pas

//about line 12
uses
  // -- patch 
  // use the modified System.Sensors
  System.Sensors;
...
// about line 70
class constructor TPermission.Create;
var
  PackageInfo: JPackageInfo;
  PackageManager: JPackageManager;
  Activity: JActivity;
  LContext: JContext;
begin
  // -- patch 
  // Activity := TJNativeActivity.Wrap
  // (PANativeActivity(System.DelphiActivity)^.clazz)
  LContext := TJContextWrapper.Wrap(System.JavaContext);
  PackageManager := LContext.getPackageManager();
  PackageInfo := PackageManager.getPackageInfo
    (LContext.getApplicationContext.getPackageName,
    TJPackageManager.JavaClass.GET_PERMISSIONS);
  FPermissions := PackageInfo.requestedPermissions;
end;
...
// about line 100
type
  TAndroidGeocoder = class(TGeocoder)
  private type
    TGeocoderRunnable = class(TJavaLocal, JRunnable)
    private
      FCoord: TLocationCoord2D;
      FLGeocoder: JGeocoder;
    public
      constructor Create(ACoord: TLocationCoord2D; AGeocoder: JGeocoder);
      procedure run; cdecl;
    end;
  private
  class var
    FGeocoder: JGeocoder;
    // FActivity: JActivity; // -- patch 
    FActivity: JContextWrapper; // -- patch 
...
// about line 130
  TUIAndroidLocationSensor = class(TCustomLocationSensor)
  private
    FPermitted: Boolean;
    // FActivity: JNativeActivity; // -- patch 
    FActivity: JContext; // -- patch 
    FLastValue: JLocation;
    FLocationManager: JLocationManager;
    FAccuracy: TLocationAccuracy;
...
// about line 1500
constructor TUIAndroidLocationSensor.Create(AManager: TSensorManager);
var
  LocationService: JObject;
begin
  inherited;
  // FActivity := TJNativeActivity.Wrap
  // (PANativeActivity(System.DelphiActivity)^.clazz); // -- patch 
  FActivity := TJContext.Wrap(System.JavaContext); // -- patch 
  LocationService := FActivity.getSystemService
    (TJContext.JavaClass.LOCATION_SERVICE);
  if Assigned(LocationService) then
    FLocationManager := TJLocationManager.Wrap((LocationService as ILocalObject)
      .GetObjectID);
end;
...
// about line 1530
  function RunIfPossible(var ARunnable: TLocationRunnable;
    var AListener: TLocationListener; AProviderName: JString): Boolean;
  var
    Provider: JLocationProvider;
    LHandler: JHandler;
  begin
    Result := False;
    if FLocationManager.isProviderEnabled(AProviderName) then
    begin
      if AListener = nil then
        AListener := TLocationListener.Create(Self);
      Provider := FLocationManager.getProvider(AProviderName);
      if Provider <> nil then
      begin
        ARunnable := TLocationRunnable.Create(FLocationManager, AListener,
          AProviderName);
        // FActivity.runOnUiThread(ARunnable); // --patch 
        // -- patch 
        // You can use post method of Handler instead runOnUiThread in this case.
        // more info here: http://developer.android.com/guide/topics/fundamentals/processes-and-threads.html
        LHandler := TJHandler.JavaClass.init;
        LHandler.post(ARunnable);
        Result := True;
      end;
    end;
  end;
...
// about line 1730
class constructor TAndroidGeocoder.Create;
begin
  // -- patch 
  // FActivity := TJNativeActivity.Wrap
  // (PANativeActivity(System.DelphiActivity)^.clazz);
  FActivity := TJContextWrapper.Wrap(System.JavaContext);
  FGeocoder := TJGeocoder.JavaClass.init(FActivity);
end;

然后你可以像这样使用LocationSensor:
uses System.Sensors, System.Android.Sensors;
...
var
  FSensors: TSensorArray;
  Sensor: TCustomSensor;
begin
  TSensorManager.Current.Active := true;
  FSensors := TSensorManager.Current.GetSensorsByCategory(TSensorCategory.Location);

  FSensor := nil;
  for Sensor in FSensors do
  begin
    if TCustomLocationSensor(Sensor).SensorType = TLocationSensorType.GPS then
    begin
      FSensor := TCustomLocationSensor(Sensor);
      Break;
    end;
  end;

  if not Assigned(FSensor) then
    Exit; { no location sensor is available }

  { start the sensor if it is not started }
  if not FSensor.Started then
    FSensor.Start;

我从文章中添加了主要的代码更改。现在可以了吗? - Rusland
比以前更好。如果它能工作,那就比被接受的答案更好。 - daemmie
它是工作方法。我在我的应用程序中使用它。然而,我卡在了计时器上 - TTimer在服务中无法工作。有什么建议吗? - Rusland

1
如果TTimer不按预期工作,请尝试在匿名线程中完成所有操作,并在主线程中使用TThread.CurrentThread.Sleep。
function TServiceModule.AndroidServiceStartCommand(const Sender: TObject;
  const Intent: JIntent; Flags, StartId: Integer): Integer;
begin
  Result := TJService.JavaClass.START_STICKY;
TThread.CreateAnonymousThread(procedure begin repeat TThread.Current.Sleep(MSecsPerSec); TThread.CreateAnonymousThread(procedure DoStuff(); end).Start; TThread.Current.Sleep(MSecsPerSec); until (TThread.Current.CheckTerminated); end).Start; end;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接