如何将布尔值(或整数)传递给意图并读取它(以检测我的 activity 是从 Android AlarmManager 启动的)?
How to pass boolean (or integer) to intent and read it (to detect that my activity was started from Android AlarmManager)?
我可以使用 Android AlarmManager 将我的 android 应用程序设置为在指定时间启动。效果很好,我使用 this manual and this 论坛了解详细信息(使用 google 翻译器)。
所以我从 Java 代码 创建 DEX 文件(从 XE7 你可以简单地 attach JAR without creating dex(!)). To detect if My app was started from AlarmManager I decided to put boolean var to intent, using this java 来自 Whosebug 的手册,所以我添加到 java 这行代码:
TestLauncher.putExtra("StartedFromAM", true);
完整的 Java 代码,将被编译为 jar(或 dex):
package com.TestReceiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class AlarmReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Intent TestLauncher = new Intent();
TestLauncher.setClassName(context, "com.embarcadero.firemonkey.FMXNativeActivity");
TestLauncher.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
TestLauncher.putExtra("StartedFromAM", true);
context.startActivity(TestLauncher);
}
}
所以现在理论上我的 Intent 有 StartedFromAM 参数。
它可以编译成 dex 文件,问题是我无法从 Delphi 代码中读取这个布尔值 - 它总是 = 0(假)。
我试过这个:
ShowMessage(SharedActivity.getIntent.getBooleanExtra(StringToJString('StartedFromAM'), false).ToString);
ShowMessage(MainActivity.getIntent.getBooleanExtra(StringToJString('StartedFromAM'), false).ToString);
更新 1
感谢 Blong 先生,关于如何检测我的 activity 是从 Android AlarmManager 启动的,我已经找到了正确的解决方案,这个更新只是关于 Java 中的 PutExtra 代码和从 Delphi 的意图中读取额外的价值。如果你愿意,你可以跳过它。
现在我知道我可以连接 JAR 文件(我有 Berlin upd 2),而无需创建 dex。
所以我创建了新的 jar 文件——上面显示的完整 java 代码。
然后我创建了新项目,并用这段代码设置了警报
procedure SetAlarmWakeUpAdnroid(aSeconds: integer);
function getTimeAfterInSecs(Seconds: Integer): Int64;
var
Calendar: JCalendar;
begin
Calendar := TJCalendar.JavaClass.getInstance;
Calendar.add(TJCalendar.JavaClass.SECOND, Seconds);
Result := Calendar.getTimeInMillis;
end;
var
Intent: JIntent;
PendingIntent: JPendingIntent;
vRes: boolean;
begin
Intent := TJIntent.Create;
Intent.setClassName(TAndroidHelper.Context, StringToJString('com.embarcadero.firemonkey.FMXNativeActivity'));
PendingIntent := TJPendingIntent.JavaClass.getActivity(TAndroidHelper.Context, 1, Intent, 0);
TAndroidHelper.AlarmManager.&set(TJAlarmManager.JavaClass.RTC_WAKEUP, getTimeAfterInSecs(30),
PendingIntent);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
SetAlarmWakeUpAdnroid(30);
end;
然后我添加了 OnFormCreate 事件
procedure TForm1.FormCreate(Sender: TObject);
begin
ShowMessage('StartedFromAM =' + TAndroidHelper.Activity.getIntent.getBooleanExtra(StringToJString('StartedFromAM'), false).ToString);
ShowMessage('EXTRA_ALARM_COUNT = ' + TAndroidHelper.Activity.getIntent.getIntExtra(TJIntent.JavaClass.EXTRA_ALARM_COUNT, 0).ToString);
end;
当警报管理器启动我的应用程序时,我得到 EXTRA_ALARM_COUNT = 1 和 StartedFromAM = 0。
回答这个问题有几点要说:
1) 原理很好。如果 Java 代码已被正确编译并正确链接,那么当 AlarmManager
通过您的 BroadcastReceiver
调用您的 activity 时,这样的代码将按您预期的方式运行:
uses
Androidapi.Helpers,
Androidapi.JNI.GraphicsContentViewText;
...
var
Intent: JIntent;
...
Intent := TAndroidHelper.Activity.getIntent;
if Intent.getBooleanExtra(StringToJString('StartedFromAM'), False) then
lblInfo.Text := 'Started by Alarm Manager through Broadcast Receiver';
2) Delphi 包含 Java .jar 文件存在潜在问题。在没有任何其他证据的情况下,我会假设您在您的代码看起来可行但似乎无法运行的情况下遇到了这个问题。
在使用包含在您的 Delphi Android 项目中的 .jar 文件时,如果您更改或重建 .jar 文件,Delphi请注意它已更新,因此仍然包含您最初添加的 .jar 版本中的链接。
要解决这个问题,您可以清理项目(右键单击项目管理器树控件中的项目名称并选择清理)。如果您想绝对确定您已经解决了问题,您应该:
- 清理项目(确保删除项目的 Android 输出目录)
- 从项目的Android、库列表
中删除 .jar 文件
- 关闭 Delphi 中的项目
- 重建您的 .jar 文件
- 重新打开 Delphi
中的项目
- 将 .jar 文件重新添加到项目的 Android、库列表
我自己在查看这个警报管理器场景时遇到了这个问题。
注意我指的是 .jar 文件。这就是您从 Delphi XE7 onwards. In XE6 you must create a merged classes.dex file 从 Delphi 的 classes.dex 和您的 .jar 文件添加到您的项目并使用它的内容,并且由于问题涉及创建 DEX 文件,也许按照规定的步骤出现问题?这比将 .jar 添加到项目要麻烦得多。
3) linked source article covers 2 options for invoking your application from the AlarmManager
。您已经了解了您在 Java 中实现的通过广播接收器的方法 - 这增加了构建它的复杂性。
该文章中引用的另一种方法是 AlarmManager
直接触发您的 activity。现在你可以说 "Well how do I know if the activity was triggered through an alarm, when my broadcast receiver is out of the picture?" ,答案是 activity 意图将自动包含一个额外的整数,称为 EXTRA_ALARM_COUNT
.
这意味着您可以像这样编写一些代码,比如在您的 OnCreate
事件处理程序中,并且完全避免自定义 Java 代码:
uses
Androidapi.Helpers,
Androidapi.JNI.GraphicsContentViewText;
...
var
Intent: JIntent;
...
Intent := TAndroidHelper.Activity.getIntent;
if Intent.getIntExtra(TJIntent.JavaClass.EXTRA_ALARM_COUNT, 0) > 0 then
lblInfo.Text := 'Started by Alarm Manager through FMX Activity';
4) 您会注意到我使用的是 TAndroidHelper.Activity
而不是 SharedActivity
。后者在 Delphi 10 西雅图改为前者。
我可以使用 Android AlarmManager 将我的 android 应用程序设置为在指定时间启动。效果很好,我使用 this manual and this 论坛了解详细信息(使用 google 翻译器)。
所以我从 Java 代码 创建 DEX 文件(从 XE7 你可以简单地 attach JAR without creating dex(!)). To detect if My app was started from AlarmManager I decided to put boolean var to intent, using this java 来自 Whosebug 的手册,所以我添加到 java 这行代码:
TestLauncher.putExtra("StartedFromAM", true);
完整的 Java 代码,将被编译为 jar(或 dex):
package com.TestReceiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class AlarmReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Intent TestLauncher = new Intent();
TestLauncher.setClassName(context, "com.embarcadero.firemonkey.FMXNativeActivity");
TestLauncher.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
TestLauncher.putExtra("StartedFromAM", true);
context.startActivity(TestLauncher);
}
}
所以现在理论上我的 Intent 有 StartedFromAM 参数。
它可以编译成 dex 文件,问题是我无法从 Delphi 代码中读取这个布尔值 - 它总是 = 0(假)。
我试过这个:
ShowMessage(SharedActivity.getIntent.getBooleanExtra(StringToJString('StartedFromAM'), false).ToString);
ShowMessage(MainActivity.getIntent.getBooleanExtra(StringToJString('StartedFromAM'), false).ToString);
更新 1
感谢 Blong 先生,关于如何检测我的 activity 是从 Android AlarmManager 启动的,我已经找到了正确的解决方案,这个更新只是关于 Java 中的 PutExtra 代码和从 Delphi 的意图中读取额外的价值。如果你愿意,你可以跳过它。
现在我知道我可以连接 JAR 文件(我有 Berlin upd 2),而无需创建 dex。 所以我创建了新的 jar 文件——上面显示的完整 java 代码。 然后我创建了新项目,并用这段代码设置了警报
procedure SetAlarmWakeUpAdnroid(aSeconds: integer);
function getTimeAfterInSecs(Seconds: Integer): Int64;
var
Calendar: JCalendar;
begin
Calendar := TJCalendar.JavaClass.getInstance;
Calendar.add(TJCalendar.JavaClass.SECOND, Seconds);
Result := Calendar.getTimeInMillis;
end;
var
Intent: JIntent;
PendingIntent: JPendingIntent;
vRes: boolean;
begin
Intent := TJIntent.Create;
Intent.setClassName(TAndroidHelper.Context, StringToJString('com.embarcadero.firemonkey.FMXNativeActivity'));
PendingIntent := TJPendingIntent.JavaClass.getActivity(TAndroidHelper.Context, 1, Intent, 0);
TAndroidHelper.AlarmManager.&set(TJAlarmManager.JavaClass.RTC_WAKEUP, getTimeAfterInSecs(30),
PendingIntent);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
SetAlarmWakeUpAdnroid(30);
end;
然后我添加了 OnFormCreate 事件
procedure TForm1.FormCreate(Sender: TObject);
begin
ShowMessage('StartedFromAM =' + TAndroidHelper.Activity.getIntent.getBooleanExtra(StringToJString('StartedFromAM'), false).ToString);
ShowMessage('EXTRA_ALARM_COUNT = ' + TAndroidHelper.Activity.getIntent.getIntExtra(TJIntent.JavaClass.EXTRA_ALARM_COUNT, 0).ToString);
end;
当警报管理器启动我的应用程序时,我得到 EXTRA_ALARM_COUNT = 1 和 StartedFromAM = 0。
回答这个问题有几点要说:
1) 原理很好。如果 Java 代码已被正确编译并正确链接,那么当 AlarmManager
通过您的 BroadcastReceiver
调用您的 activity 时,这样的代码将按您预期的方式运行:
uses
Androidapi.Helpers,
Androidapi.JNI.GraphicsContentViewText;
...
var
Intent: JIntent;
...
Intent := TAndroidHelper.Activity.getIntent;
if Intent.getBooleanExtra(StringToJString('StartedFromAM'), False) then
lblInfo.Text := 'Started by Alarm Manager through Broadcast Receiver';
2) Delphi 包含 Java .jar 文件存在潜在问题。在没有任何其他证据的情况下,我会假设您在您的代码看起来可行但似乎无法运行的情况下遇到了这个问题。
在使用包含在您的 Delphi Android 项目中的 .jar 文件时,如果您更改或重建 .jar 文件,Delphi请注意它已更新,因此仍然包含您最初添加的 .jar 版本中的链接。
要解决这个问题,您可以清理项目(右键单击项目管理器树控件中的项目名称并选择清理)。如果您想绝对确定您已经解决了问题,您应该:
- 清理项目(确保删除项目的 Android 输出目录)
- 从项目的Android、库列表 中删除 .jar 文件
- 关闭 Delphi 中的项目
- 重建您的 .jar 文件
- 重新打开 Delphi 中的项目
- 将 .jar 文件重新添加到项目的 Android、库列表
我自己在查看这个警报管理器场景时遇到了这个问题。
注意我指的是 .jar 文件。这就是您从 Delphi XE7 onwards. In XE6 you must create a merged classes.dex file 从 Delphi 的 classes.dex 和您的 .jar 文件添加到您的项目并使用它的内容,并且由于问题涉及创建 DEX 文件,也许按照规定的步骤出现问题?这比将 .jar 添加到项目要麻烦得多。
3) linked source article covers 2 options for invoking your application from the AlarmManager
。您已经了解了您在 Java 中实现的通过广播接收器的方法 - 这增加了构建它的复杂性。
该文章中引用的另一种方法是 AlarmManager
直接触发您的 activity。现在你可以说 "Well how do I know if the activity was triggered through an alarm, when my broadcast receiver is out of the picture?" ,答案是 activity 意图将自动包含一个额外的整数,称为 EXTRA_ALARM_COUNT
.
这意味着您可以像这样编写一些代码,比如在您的 OnCreate
事件处理程序中,并且完全避免自定义 Java 代码:
uses
Androidapi.Helpers,
Androidapi.JNI.GraphicsContentViewText;
...
var
Intent: JIntent;
...
Intent := TAndroidHelper.Activity.getIntent;
if Intent.getIntExtra(TJIntent.JavaClass.EXTRA_ALARM_COUNT, 0) > 0 then
lblInfo.Text := 'Started by Alarm Manager through FMX Activity';
4) 您会注意到我使用的是 TAndroidHelper.Activity
而不是 SharedActivity
。后者在 Delphi 10 西雅图改为前者。