android - Delphi AndroidAPI 运动检测

标签 android delphi firemonkey

我想直接使用 AndroidApi 编写运动检测器(加速度计)代码。我目前已经使用 TMotionSensor 和 TSensorManager 测试了实现(根据 Embarcadero 示例),但两者似乎都存在功耗问题(即手机变热)。

我的 TSensorManager 实现如下所示:

procedure TfrmTabbed.InitSensorMan;
var
  FSensors: TSensorArray;
  Sensor: TCustomSensor;
begin
  TSensorManager.Current.Activate;
  FSensors := TSensorManager.Current.GetSensorsByCategory(TSensorCategory.Motion);
  FSensor := nil;
  for Sensor in FSensors do
  begin
    if TCustomMotionSensor(Sensor).SensorType = TMotionSensorType.Accelerometer3D then
    begin
      FSensor := TCustomMotionSensor(Sensor);
      Break;
    end;
  end;
  MotionTimer.Interval := 250; 
  MotionTimer.Active := True;
end;

现在,使用 How to detect movement of an android device?作为引用,我开始编写这样的代码:

uses
  Androidapi.Sensor,
  Androidapi.JNI.JavaTypes;

{$R *.fmx}

procedure TForm2.FormCreate(Sender: TObject);
var
  Obj: JObject;
  SensorManager: JSensorManager;
begin

  Obj := TAndroidHelper.Context.getSystemService(TJContext.JavaClass.SENSOR_SERVICE);
  if Obj <> nil then
  begin
     SensorManager := TJsensorManager.Wrap(Obj);

  end;

我想任何熟悉这个领域的人都会意识到没有JSensorManager。在 C:\Program Files (x86)\Embarcadero\Studio\18.0\source 中的任何位置声明.有一个Androidapi.JNI.Telephony.pas , 但没有 Androidapi.JNI.Sensor(s).pas !

我的问题是,是否可以通过这种方式从 Delphi 访问 SENSOR_SERVICE,如果可以,我该如何实现?

附录

我试过 Java2op。似乎需要非常特定的 JDK 版本(1.7.25?)才能不产生“预期的类或接口(interface)”错误。所以我尝试了 Java2Pas反而。免费版仅解析 Android.jar,但这似乎足以满足我的目的。

最佳答案

对于那些试图在 Delphi Android 10.x 中尝试做相同(或类似)事情的人,尤其是使用 Listeners,这是我(几乎完成)的回答。

注意:

  1. SensorListener 已在 Android 中弃用。请改用 SensorEventListener。

  2. Java2pas 在 android.hardware.SensorEventListener.pas 中错误地编码了 JSensorEventListener。它是 JSensorEventListener = interface(JObject)。它必须更正为 JSensorEventListener = interface(IJavaInstance)

  3. android.hardware.SensorEvent 中,JSensorEvent 中缺少 values 属性和 _Getvalues 函数声明。只需从 JSensorEventClass 复制它们。

代码如下:

unit Unit2;

interface

uses    
 System.SysUtils, System.Types, System.UITypes, System.Classes,
 System.Variants,
 FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
 FMX.Controls.Presentation, FMX.StdCtrls
 , Androidapi.JNIBridge
 , Androidapi.JNI.Embarcadero
 , Androidapi.JNI.GraphicsContentViewText
 , androidapi.JNI.JavaTypes
 , AndroidApi.JNI.Location
 , Androidapi.JNI.Os
 // java2pas gen'd units (modified as noted above)
 , android.hardware.SensorManager
 , android.hardware.Sensor
 , android.hardware.SensorEventListener
 , android.hardware.SensorEvent
 , FMX.ScrollBox, FMX.Memo
 ;

type

  TSensorEventListener = class;

  TForm2 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    FSensorManager: JSensorManager;
    FDefaultSensor: JSensor;
    SensorEventListener: TSensorEventListener;
    FStarted: Boolean;
    procedure StartApi;
    procedure StopApi;
  public
    { Public declarations }
  end;

  TSensorEventListener = class(TJavaLocal, JSensorEventListener)
  private
    [weak]
    FParent: TForm2;
  public
    constructor Create(AParent: TForm2);
    procedure onAccuracyChanged(JSensorparam0 : JSensor; Integerparam1 : Integer) ; cdecl;
    procedure onSensorChanged(JSensorEventparam0 : JSensorEvent) ; cdecl;
  end;

var
  Form2: TForm2;

implementation

uses
  Androidapi.Helpers
  , Androidapi.JNI.Net
  , FMX.Helpers.Android
  ;

procedure TForm2.Button1Click(Sender: TObject);
begin
  if Fstarted then
    StopApi
  else
    StartApi;
end;

procedure TForm2.FormCreate(Sender: TObject);
begin
  FStarted := False;
end;

procedure TForm2.StartApi;
var
  SensorManagerService: JObject;
begin
  if not Assigned(FSensorManager) then
  begin
    SensorManagerService := TAndroidHelper.Context.getSystemService(TJContext.JavaClass.SENSOR_SERVICE);
    FSensorManager := TJSensorManager.Wrap((SensorManagerService as ILocalObject).GetObjectID);
    if not Assigned(SensorEventListener) then
      SensorEventListener := TSensorEventListener.Create(Self);
    FDefaultSensor := FSensorManager.getDefaultSensor(TJSensorManager.JavaClass.SENSOR_ACCELEROMETER);
  end;
  FSensorManager.registerListener(SensorEventListener, FDefaultSensor, TJSensorManager.JavaClass.SENSOR_DELAY_NORMAL);
  Memo1.Lines.Add(DateTimeToStr(Now) + ' started');
  FStarted := True;
end;

procedure TForm2.StopApi;
begin
  if Assigned(SensorEventListener) then
    FSensorManager.unregisterListener(SensorEventListener);
  Memo1.Lines.Add(DateTimeToStr(Now) + ' stopped');
  FStarted := False;
end;

{ TSensorEventListener }

constructor TSensorEventListener.Create(AParent: TForm2);
begin
  inherited Create;
  FParent := AParent;
end;

procedure TSensorEventListener.onAccuracyChanged(JSensorparam0: JSensor;
  Integerparam1: Integer);
begin
   // do stuff
end;

procedure TSensorEventListener.onSensorChanged(
  JSensorEventparam0: JSensorEvent);
begin
   // do stuff, especially with the JSensorEventparam0.values
end;

关于android - Delphi AndroidAPI 运动检测,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46122825/

相关文章:

java - 对于设置字体大小,android sp、px 或 pt 中最喜欢的字体大小

android studio版本控制无法忽略文件

android - 允许多人登录 Google Play 游戏服务?

delphi - 在纯 ipv6 网络上使用 Indy IdTelnet

delphi - 当没有外部上下文时,过程变量和匿名函数是否等效?

android - Android 上蓝牙扫描和发现的差异

delphi - Delphi-更改TComboBox的OnChange

android - 如何在 firemonkey 中获取 Android 5 上的 IMEI?

delphi - LiveBinding值无法通过代码设置

android - 如何在知道 Jnet_Uri 的情况下将文件加载到 Android 上的流中?