【Delphi】中使用消息Messages(八)Android 系统消息感知

19 篇文章 0 订阅
9 篇文章 1 订阅

目录

一、实现android广播消息事件绑定

二、在onReceive中实现接收系统广播消息处理:

三、注册(订阅)系统状态变化消息广播:

四、控件整体定义:


上一节我提出了两个问题:

  1. App中主动调用android系统中蓝牙打开功能,如何知道用户是否真的打开了蓝牙?
  2. App运行的过程中,如何自动感知用户的某些操作,例如:打开或者关闭蓝牙功能、打开或者关闭WIFI功能等?

其中第一个问题在上一节我们已经解决,本节来我们解决第二个问题,就是实时感知Android系统的状态变化,通过实时感知可以是我们开发的App操作流程更友好,其中就使用到Delphi中的RTL消息机制。

android系统状态的变化包括病不限于:蓝牙状态变化、WI-FI状态变化、电源状态变化、网络状态变化、屏幕点亮和关闭等等。

要实现解决第二个问题,我们的思路步骤如下:

一、实现android广播消息事件绑定

uses
   ...
   Androidapi.JNIBridge,
   Androidapi.JNI.Embarcadero,
   Androidapi.JNI.GraphicsContentViewText;

type
   // 接收系统广播通知消息类
   TBroadcastReceiver = class(TJavaLocal, JFMXBroadcastReceiverListener)
   public
     // 实现接收事件
     procedure onReceive(context: JContext; intent: JIntent); cdecl;
   end;

二、在onReceive中实现接收系统广播消息处理:

onReceive函数返回两个参数,一个是context,第二个是intent。我们主要关注的是intent参数,在intent参数中携带有我们需要的信息。我们在onReceive中实现了蓝牙、WIFI、电源、网络状态变化的消息处理。注意在收到系统的广播消息后,我们通过

        myMessage := TMessageNotification.Create(FmyMSG);
        TMessageManager.DefaultManager.SendMessage(nil,myMessage,True);

也就是RTL消息机制发送给了外边的控件对象,实际上就是我们编写的(TReceiver_State)控件。

procedure TBroadcastReceiver.onReceive(context: JContext; intent: JIntent);
var
	action,S: String;
  iState: Integer;
  FmyMSG: TmyMSG;
  myMessage : TMessage;
  jo : TJSONObject;
  B : Boolean;
begin
  action := JStringToString( intent.getAction );
  //网络连接广播
                              { 'android.net.conn.CONNECTIVITY_CHANGE'}
  if action = JStringToString(TJConnectivityManager.JavaClass.CONNECTIVITY_ACTION) then
     begin
       iState := intent.getIntExtra( TJConnectivityManager.JavaClass.EXTRA_NETWORK_TYPE,0);
       FmyMSG.msg_State := iState;
       FmyMSG.msg_TYPE  := TMsgType.mtNetConnectState;

       jo := TJSONObject.Create;
       try
         //1、获取网络类型
         iState := intent.getIntExtra( TJConnectivityManager.JavaClass.EXTRA_NETWORK_TYPE,0);
         case iState of
           0 : jo.AddPair('EXTRA_NETWORK_TYPE','Mobile'); //手机流量
           1 : jo.AddPair('EXTRA_NETWORK_TYPE','WIFI');   //WIFI
           7 : jo.AddPair('EXTRA_NETWORK_TYPE','BlueTooth'); //BlueTooth
         else //其它
           jo.AddPair('EXTRA_NETWORK_TYPE','Other');
         end;
         //2、获取网络信息
         S := JStringToString( intent.getStringExtra(TJConnectivityManager.JavaClass.EXTRA_EXTRA_INFO));
         jo.AddPair('EXTRA_EXTRA_INFO',S);
         //3、 EXTRA_NO_CONNECTIVITY
         B := intent.getBooleanExtra(TJConnectivityManager.JavaClass.EXTRA_NO_CONNECTIVITY,false);
         if B then
            jo.AddPair('EXTRA_NO_CONNECTIVITY','true')
         else
            jo.AddPair('EXTRA_NO_CONNECTIVITY','false');
         FmyMSG.msg_Content := jo.ToString;
       finally
         jo.Free;
       end;

       myMessage := TMessage<TmyMSG>.Create(FmyMSG);
       TMessageManager.DefaultManager.SendMessage(nil,myMessage,True);

       Exit;
     end;
  

  //1. 处理蓝牙广播消息
  if action = JStringToString(TJBluetoothAdapter.JavaClass.ACTION_STATE_CHANGED) then
     begin
       //获取蓝牙状态
       iState := intent.getIntExtra( TJBluetoothAdapter.JavaClass.EXTRA_STATE ,0);
       FmyMSG.msg_State := iState;
       FmyMSG.msg_TYPE := TMsgType.mtBlueToothState;

       case FmyMSG.msg_State of
          2 : FmyMSG.msg_Content := 'STATE_CONNECTED';     //bts_STATE_CONNECTED     2
          1 : FmyMSG.msg_Content := 'STATE_CONNECTING';    //bts_STATE_CONNECTING    1
          0 : FmyMSG.msg_Content := 'STATE_DISCONNECTED';  //bts_STATE_DISCONNECTED  0
          3 : FmyMSG.msg_Content := 'DISCONNECTING';       //bts_STATE_DISCONNECTING 3
          10: FmyMSG.msg_Content := 'STATE_OFF';           //bts_STATE_OFF           10
          12: FmyMSG.msg_Content := 'STATE_ON';            //bts_STATE_ON            12
          13: FmyMSG.msg_Content := 'STATE_TURNING_OFF';   //bts_STATE_TURNING_OFF   13
          11: FmyMSG.msg_Content := 'STATE_TURNING_ON';    //bts_STATE_TURNING_ON    11
        end;

       //通知控件处理此事件
       myMessage := TMessage<TmyMSG>.Create(FmyMSG);
       TMessageManager.DefaultManager.SendMessage(nil,myMessage,True);

       Exit;
     end;
  //2. 处理WIFI广播消息
  if action = JStringToString(TJWifiManager.JavaClass.WIFI_STATE_CHANGED_ACTION) then
     begin
       //获取WIFI状态
       iState := intent.getIntExtra( TJWifiManager.JavaClass.EXTRA_WIFI_STATE ,0);
       FmyMSG.msg_State := iState;
       FmyMSG.msg_TYPE := TMsgType.mtWIFIState;

       case FmyMSG.msg_State of
          1: FmyMSG.msg_Content := 'WIFI_STATE_DISABLED';   // wfs_WIFI_STATE_DISABLED = 1
          0: FmyMSG.msg_Content := 'WIFI_STATE_DISABLING';  // wfs_WIFI_STATE_DISABLING = 0,
          3: FmyMSG.msg_Content := 'WIFI_STATE_ENABLED';    // wfs_WIFI_STATE_ENABLED = 3,
          2: FmyMSG.msg_Content := 'WIFI_STATE_ENABLING';   // wfs_WIFI_STATE_ENABLING = 2,
          4: FmyMSG.msg_Content := 'WIFI_STATE_UNKNOWN';    // wfs_WIFI_STATE_UNKNOWN = 4
        end;

       //通知控件处理此事件

       myMessage := TMessage<TmyMSG>.Create(FmyMSG);
       TMessageManager.DefaultManager.SendMessage(nil,myMessage,True);
       Exit;
     end;
  //3. 处理电源变化
   if action = 'android.intent.action.BATTERY_CHANGED' then
      begin
        FmyMSG.msg_TYPE := mtPowerState;
        jo := TJSONObject.Create;
        try
          //获取电源电量 参考:http://www.android-doc.com/reference/android/os/BatteryManager.html#EXTRA_LEVEL
          iState := intent.getIntExtra(StringToJString('level') ,0);
          jo.AddPair('level',iState.ToString);
          //是否插上电源, 0 means it is on battery, other constants are different types of power sources.
          iState := intent.getIntExtra(StringToJString('plugged') ,0);
          if iState <> 0 then
             jo.AddPair('plugged','true')
          else
             jo.AddPair('plugged','false');
          //是否是电池供电
          //iState := intent.getIntExtra(StringToJString('present') ,0);
          //jo.AddPair('present',iState);
          //电池温度
          //iState := intent.getIntExtra(StringToJString('temperature') ,0);
          //jo.AddPair('temperature',iState);

          //电池电压
          iState := intent.getIntExtra(StringToJString('voltage') ,0);
          jo.AddPair('voltage',iState.ToString);

          FmyMSG.msg_Content :=  jo.ToString;
        finally
          jo.Free;
        end;
        iState := intent.getIntExtra(StringToJString('level') ,0);
        FmyMSG.msg_State := iState;

        //通知控件处理此事件
        myMessage := TMessage<TmyMSG>.Create(FmyMSG);
        TMessageManager.DefaultManager.SendMessage(nil,myMessage,True);
        Exit;
      end;
end;

三、注册(订阅)系统状态变化消息广播:

我们需要接收(监听)什么状态,我们就注册什么状态,这样注册后的项目如果状态发生变化,我们就能够在第二步定义的onReceive事件中收到消息。在注册系统广播消息的时候,我们提前d订阅了一个我们自己的消息接收器FMessageSubscriptionID。

function TReceiver_State.Register_Reveiver(var errmsg: string): Boolean;
begin
  //如果集合为空,表示没有选择
  if FmsgTypes = [] then
     begin
       errmsg := '至少需要选择一个监测项!';
       Exit(False);
     end;

  // 注册状态变化消息接收系统
  //1. 注册消息接收
  {$IFDEF android}
  FMessageSubscriptionID := TMessageManager.DefaultManager.SubscribeToMessage
    (TMessage<TmyMSG>, ProcessMsgEvent);

  //初始化 过滤器

  FFilter := TJIntentFilter.JavaClass.init;

  //监听蓝牙消息
  if mtBlueToothState in FMsgTypes then
     begin
      FFilter.addAction(TJBluetoothAdapter.JavaClass.ACTION_STATE_CHANGED);
      //ShowMessage('mtBlueToothState');
     end;

  //监听WIFI状态
  if mtWIFIState in FMsgTypes then
     begin
       FFilter.addAction(TJWifiManager.JavaClass.WIFI_STATE_CHANGED_ACTION);
       //ShowMessage('mtWIFIState');
     end;

  //监听电源变化
  if mtPowerState in FMsgTypes  then
     begin
       FFilter.addAction(StringToJString('android.intent.action.BATTERY_CHANGED'));
       //ShowMessage('mtPowerState');
     end;

  //网络状态变化广播
  if mtNetConnectState in FMsgTypes  then
     FFilter.addAction(TJConnectivityManager.JavaClass.CONNECTIVITY_ACTION);
                        {'android.net.conn.CONNECTIVITY_CHANGE'}


  //加入通用类别
	FFilter.addCategory(StringToJString('android.intent.category.DEFAULT'));

  //1. 动态注册广播接受者
  try
    TAndroidHelper.Context.registerReceiver(FReceiver, FFilter);
    Result  := True;
    //ShowMessage('OK');
  except on E: Exception do
    begin
      errmsg := E.Message;
      Result := False;
    end;
  end;
  //内部记录是否处于监测状体 True 表示是处于监测状态
  FOpened := Result;
  {$ENDIF}
end;

上述代码也许一下看不明白,因为我把android系统状态变化封装成了一个控件(TReceiver_State),这样使用起来将会非常方便

四、控件整体定义:

事实上我们需要解决的是 TBroadcastReceiver 和控件TReceiver_State之间的消息传递,使用的是RTL跨平台的消息机制。从而实现控件TReceiver_State的事件(OnStateChange)触发。

 TReceiver_State = class(TComponent)
  private
    { Private declarations }
    {$IFDEF  android}
    FListener: TBroadcastReceiver;
		FReceiver: JFMXBroadcastReceiver;
		FFilter  : JIntentFilter;
    {$ENDIF}

    FMsgTypes : TMsgTypes;
    FOpened   : Boolean;   //是否处于监听状态, True 是,否则 False

    FOnStateChange : TOnStateChange;

    FMessageSubscriptionID  : Integer;  //接收消息ID

    procedure SetMsgTypes(value : TMsgTypes);  //属性设置过程

  protected
    { Protected declarations }
    procedure ProcessMsgEvent(const Sender: TObject; const M: TMessage);
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure  Loaded;override;
    //注册广播监听
    function Register_Reveiver(var errmsg : string) : Boolean;
    //取消广播监听
    procedure UnRegister_Reveiver;
  published
    { Published declarations }
    property OnStateChange: TOnStateChange read FOnStateChange write FOnStateChange;
    property Receivers : TMsgTypes read FMsgTypes  write SetMsgTypes; // default [TMsgType.mtBlueToothState,TMsgType.mtWIFIState]; //默认监测蓝牙选项
  end;

constructor TReceiver_State.Create;
begin
  inherited;
  FOpened   := False;  //默认是没有打开监听
  //FMsgTypes := [TMsgType.mtBlueToothState];

  {$IFDEF  android}
    //1. 创建系统消息接收者
	  FListener := TBroadcastReceiver.Create;

    //2. 初始化注册接收器
    FReceiver := TJFMXBroadcastReceiver.JavaClass.init(FListener);
  {$ENDIF}
end;

destructor TReceiver_State.Destroy;
begin
  //解除广播消息接收
  {$IFDEF  android}
  TAndroidHelper.Context.unregisterReceiver(FReceiver);
  {$ENDIF}
  UnRegister_Reveiver;

  inherited;
end;

procedure TReceiver_State.Loaded;
begin
  inherited;
  //FMsgTypes := [TMsgType.mtBlueToothState];
end;

Delphi Message 系列文章到此全部结束!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Delphi和Python之间通讯可以使用消息队列来实现,具体步骤如下: 1. 在Delphi创建一个消息队列用于接收Python发来的消息。 2. 在Python使用消息队列模块创建一个消息队列,并将需要发送的消息放入队列。 3. Delphi通过轮询消息队列来获取Python发送的消息,并根据消息内容进行相应的处理。 4. Python可以通过轮询消息队列来获取Delphi发送的消息,并根据消息内容进行相应的处理。 下面是一个简单的示例代码: 在Delphi: ```delphi uses Windows, Messages; const WM_PYTHON_MSG = WM_USER + 1; // 定义Python消息ID type TForm1 = class(TForm) private { Private declarations } procedure HandlePythonMsg(var Msg: TMessage); message WM_PYTHON_MSG; public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.HandlePythonMsg(var Msg: TMessage); var strMsg: string; begin strMsg := PChar(Msg.LParam); // 获取Python发送的消息 // 根据消息内容进行相应的处理 ShowMessage(strMsg); end; ``` 在Python: ```python import win32api import win32con import win32event import win32file import struct WM_PYTHON_MSG = win32con.WM_USER + 1 # 定义Python消息ID def send_msg_to_delphi(msg): hwnd = win32gui.FindWindow(None, "DelphiForm") # 获取Delphi窗口句柄 if hwnd: win32api.PostMessage(hwnd, WM_PYTHON_MSG, 0, msg) # 发送消息Delphi else: print("Can't find Delphi window") def recv_msg_from_delphi(): handle = win32event.CreateEvent(None, 0, 0, None) # 创建事件 overlapped = win32file.OVERLAPPED() overlapped.hEvent = handle buf = struct.pack("L", WM_PYTHON_MSG) # 构造消息格式 (err, msg) = win32file.ReadFile(handle, buf, overlapped) # 从消息队列获取消息 if err == win32file.ERROR_IO_PENDING: win32event.WaitForSingleObject(handle, 1000) # 等待事件 (err, msg) = win32file.GetOverlappedResult(handle, overlapped, True) if err == 0: print("Error reading from message queue") else: return msg.decode("utf-8") ``` 上述示例代码Delphi的 HandlePythonMsg 过程用于处理接收到的Python消息,Python的 send_msg_to_delphi 函数用于将消息发送给Delphi,recv_msg_from_delphi 函数用于从Delphi接收消息。注意,Delphi消息ID和Python消息ID必须一致。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海纳老吴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值