目录
一、实现android广播消息事件绑定
二、在onReceive中实现接收系统广播消息处理:
三、注册(订阅)系统状态变化消息广播:
四、控件整体定义:
在上一节我提出了两个问题:
其中第一个问题在上一节我们已经解决,本节来我们解决第二个问题,就是实时感知Android系统的状态变化,通过实时感知可以是我们开发的App操作流程更友好,其中就使用到Delphi中的RTL消息机制。
android系统状态的变化包括病不限于:蓝牙状态变化、WI-FI状态变化、电源状态变化、网络状态变化、屏幕点亮和关闭等等。
要实现解决第二个问题,我们的思路步骤如下:
uses
...
Androidapi.JNIBridge,
Androidapi.JNI.Embarcadero,
Androidapi.JNI.GraphicsContentViewText;
type
// 接收系统广播通知消息类
TBroadcastReceiver = class(TJavaLocal, JFMXBroadcastReceiverListener)
public
// 实现接收事件
procedure onReceive(context: JContext; intent: JIntent); cdecl;
end;
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.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.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.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.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, 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 系列文章到此全部结束!