Xamarin Android:在特定时间重新打开应用程序
Xamarin Android: Reopen app at specific time
我正在努力尝试在 Xamarin 中创建一个闹钟类型的应用程序,我现在正在做的是尝试让该应用程序在特定时间重新打开,无论如何(我知道不包括重启)那是 onbootcompleted)但是当我现在关闭应用程序时,AlarmManager 广播永远不会被触发并且应用程序永远不会重新打开。
现在我正在尝试通过将 alarmmanager 设置为在我单击按钮 1 分钟后弹出广播来进行测试。
广播接收器
using Android.Content;
namespace (removed)
{
[BroadcastReceiver]
public class ServiceEventHandler : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Intent temp = new Intent();
temp.SetClass(context, typeof(MainActivity));
temp.SetFlags(ActivityFlags.NewTask);
context.StartActivity(temp);
}
}
}
清单
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="(removed)" android:versionCode="1" android:versionName="1.0" android:installLocation="auto">
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="24" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.PERSISTENT_ACTIVITY" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application android:icon="@drawable/Icon" android:label="(removed)">
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
<meta-data android:name="com.google.android.geo.API_KEY" android:value="(removed)" />
</application>
</manifest>
启动闹钟的方法
private void Test_Click(object sender, EventArgs e)
{
//StartService(new Intent(this, typeof(TestService)));
Intent wake = new Intent(this, typeof(ServiceEventHandler));
PendingIntent pending = PendingIntent.GetBroadcast(this, 0, wake, 0);
var alarmMgr = (AlarmManager)GetSystemService(AlarmService);
Calendar cal = Calendar.GetInstance(Java.Util.TimeZone.Default);
cal.Set(CalendarField.HourOfDay, DateTime.Now.Hour);
cal.Set(CalendarField.Minute, DateTime.Now.Minute + 1);
cal.Set(CalendarField.Minute, cal.Get(CalendarField.Minute) + 1);//One minute for test
alarmMgr.Set(AlarmType.RtcWakeup, cal.TimeInMillis, pending);
}
1) 您的日历可能有问题。添加:
cal.Set(CalendarField.Year, DateTime.Now.Year);
cal.Set(CalendarField.Month, DateTime.Now.Month - 1);
cal.Set(CalendarField.DayOfMonth, DateTime.Now.Day);
删除这个:
cal.Set(CalendarField.Minute, cal.Get(CalendarField.Minute) + 1);
2) 对于不同的 API 级别,您可能无法使用正确的方法。使用这个:
if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop)
{
var launchIntent = new Intent(Application.Context, typeof(SplashActivity)); //use your starting activity
var launchPendingIntent = PendingIntent.GetActivity(Application.Context, requestCode, launchIntent,
PendingIntentFlags.CancelCurrent); //use the same request code as for 'pending'
var alarmInfo = new AlarmManager.AlarmClockInfo(cal.TimeInMillis, launchPendingIntent);
alarmMgr.SetAlarmClock(alarmInfo, pending);
}
else if (Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat)
alarmMgr.SetExact(AlarmType.RtcWakeup, cal.TimeInMillis, pending);
else
alarmMgr.Set(AlarmType.RtcWakeup, cal.TimeInMillis, pending);
最终,在尝试了几周之后,我终于发现了一种无论如何都能让闹钟响起的可靠方法。总的来说,有很多关于这个过程的文档,但我发现很多文档并不全部集中在一个地方。
这就是我所做的:
在 AlarmManager
中设置的警报只有在设置它的应用程序始终为 运行 时才会持久存在。
所以解决方案是拥有一个运行和管理所有警报的后台服务。
代码:
我发现使用 Cal 留下了很大的错误空间,尤其是在使用 xamarin 时,所以我改为使用当前系统时间,并添加了现在和我希望闹钟响起之间的时间间隔
TimeSpan span = time - DateTime.Now;
long schedule = (long)(Java.Lang.JavaSystem.CurrentTimeMillis() + span.TotalMilliseconds);
这是完整的报警代码:
private void SetAlarm(DateTime time, string alarmID, int eventID, bool final)
{
if (!final)
{
Intent wake = new Intent(this, typeof(Check//Removed//Event));
wake.PutExtra("alarmID", alarmID);
PendingIntent temp = PendingIntent.GetBroadcast(this, eventID, wake, PendingIntentFlags.NoCreate);
if (temp != null)
{
temp.Cancel();
}
PendingIntent pending = PendingIntent.GetBroadcast(this, eventID, wake, PendingIntentFlags.UpdateCurrent);
var alarmMgr = (AlarmManager)GetSystemService(AlarmService);
TimeSpan span = time - DateTime.Now;
long schedule = (long)(Java.Lang.JavaSystem.CurrentTimeMillis() + span.TotalMilliseconds);
alarmMgr.SetExactAndAllowWhileIdle(AlarmType.RtcWakeup, schedule, pending);
}
else
{//Set Alarm
Intent wake = new Intent(this, typeof(//Removed//Event));
wake.PutExtra("alarmID", alarmID);
PendingIntent temp = PendingIntent.GetBroadcast(this, eventID, wake, PendingIntentFlags.NoCreate);
if (temp != null)
{
temp.Cancel();
}
PendingIntent pending = PendingIntent.GetBroadcast(this, eventID, wake, PendingIntentFlags.UpdateCurrent);
var alarmMgr = (AlarmManager)GetSystemService(AlarmService);
TimeSpan span = time - DateTime.Now;
long schedule = (long)(Java.Lang.JavaSystem.CurrentTimeMillis() + span.TotalMilliseconds);
alarmMgr.SetExactAndAllowWhileIdle(AlarmType.RtcWakeup, schedule, pending);
}
}
}
准确设置闹钟。至于让一切持久化,我让服务变得有粘性,并将其设置为每次重置时重置所有警报。这是通过检查广播是否已经存在,然后将其删除并在存在时重新安排来完成的。
PendingIntent temp = PendingIntent.GetBroadcast(this, eventID, wake, PendingIntentFlags.NoCreate);
if (temp != null)
{
temp.Cancel();
}
这个和接收启动通知的广播接收器的组合使警报尽可能持久。
我正在努力尝试在 Xamarin 中创建一个闹钟类型的应用程序,我现在正在做的是尝试让该应用程序在特定时间重新打开,无论如何(我知道不包括重启)那是 onbootcompleted)但是当我现在关闭应用程序时,AlarmManager 广播永远不会被触发并且应用程序永远不会重新打开。
现在我正在尝试通过将 alarmmanager 设置为在我单击按钮 1 分钟后弹出广播来进行测试。
广播接收器
using Android.Content;
namespace (removed)
{
[BroadcastReceiver]
public class ServiceEventHandler : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Intent temp = new Intent();
temp.SetClass(context, typeof(MainActivity));
temp.SetFlags(ActivityFlags.NewTask);
context.StartActivity(temp);
}
}
}
清单
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="(removed)" android:versionCode="1" android:versionName="1.0" android:installLocation="auto">
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="24" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.PERSISTENT_ACTIVITY" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application android:icon="@drawable/Icon" android:label="(removed)">
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
<meta-data android:name="com.google.android.geo.API_KEY" android:value="(removed)" />
</application>
</manifest>
启动闹钟的方法
private void Test_Click(object sender, EventArgs e)
{
//StartService(new Intent(this, typeof(TestService)));
Intent wake = new Intent(this, typeof(ServiceEventHandler));
PendingIntent pending = PendingIntent.GetBroadcast(this, 0, wake, 0);
var alarmMgr = (AlarmManager)GetSystemService(AlarmService);
Calendar cal = Calendar.GetInstance(Java.Util.TimeZone.Default);
cal.Set(CalendarField.HourOfDay, DateTime.Now.Hour);
cal.Set(CalendarField.Minute, DateTime.Now.Minute + 1);
cal.Set(CalendarField.Minute, cal.Get(CalendarField.Minute) + 1);//One minute for test
alarmMgr.Set(AlarmType.RtcWakeup, cal.TimeInMillis, pending);
}
1) 您的日历可能有问题。添加:
cal.Set(CalendarField.Year, DateTime.Now.Year);
cal.Set(CalendarField.Month, DateTime.Now.Month - 1);
cal.Set(CalendarField.DayOfMonth, DateTime.Now.Day);
删除这个:
cal.Set(CalendarField.Minute, cal.Get(CalendarField.Minute) + 1);
2) 对于不同的 API 级别,您可能无法使用正确的方法。使用这个:
if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop)
{
var launchIntent = new Intent(Application.Context, typeof(SplashActivity)); //use your starting activity
var launchPendingIntent = PendingIntent.GetActivity(Application.Context, requestCode, launchIntent,
PendingIntentFlags.CancelCurrent); //use the same request code as for 'pending'
var alarmInfo = new AlarmManager.AlarmClockInfo(cal.TimeInMillis, launchPendingIntent);
alarmMgr.SetAlarmClock(alarmInfo, pending);
}
else if (Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat)
alarmMgr.SetExact(AlarmType.RtcWakeup, cal.TimeInMillis, pending);
else
alarmMgr.Set(AlarmType.RtcWakeup, cal.TimeInMillis, pending);
最终,在尝试了几周之后,我终于发现了一种无论如何都能让闹钟响起的可靠方法。总的来说,有很多关于这个过程的文档,但我发现很多文档并不全部集中在一个地方。
这就是我所做的:
在 AlarmManager
中设置的警报只有在设置它的应用程序始终为 运行 时才会持久存在。
所以解决方案是拥有一个运行和管理所有警报的后台服务。
代码:
我发现使用 Cal 留下了很大的错误空间,尤其是在使用 xamarin 时,所以我改为使用当前系统时间,并添加了现在和我希望闹钟响起之间的时间间隔
TimeSpan span = time - DateTime.Now;
long schedule = (long)(Java.Lang.JavaSystem.CurrentTimeMillis() + span.TotalMilliseconds);
这是完整的报警代码:
private void SetAlarm(DateTime time, string alarmID, int eventID, bool final)
{
if (!final)
{
Intent wake = new Intent(this, typeof(Check//Removed//Event));
wake.PutExtra("alarmID", alarmID);
PendingIntent temp = PendingIntent.GetBroadcast(this, eventID, wake, PendingIntentFlags.NoCreate);
if (temp != null)
{
temp.Cancel();
}
PendingIntent pending = PendingIntent.GetBroadcast(this, eventID, wake, PendingIntentFlags.UpdateCurrent);
var alarmMgr = (AlarmManager)GetSystemService(AlarmService);
TimeSpan span = time - DateTime.Now;
long schedule = (long)(Java.Lang.JavaSystem.CurrentTimeMillis() + span.TotalMilliseconds);
alarmMgr.SetExactAndAllowWhileIdle(AlarmType.RtcWakeup, schedule, pending);
}
else
{//Set Alarm
Intent wake = new Intent(this, typeof(//Removed//Event));
wake.PutExtra("alarmID", alarmID);
PendingIntent temp = PendingIntent.GetBroadcast(this, eventID, wake, PendingIntentFlags.NoCreate);
if (temp != null)
{
temp.Cancel();
}
PendingIntent pending = PendingIntent.GetBroadcast(this, eventID, wake, PendingIntentFlags.UpdateCurrent);
var alarmMgr = (AlarmManager)GetSystemService(AlarmService);
TimeSpan span = time - DateTime.Now;
long schedule = (long)(Java.Lang.JavaSystem.CurrentTimeMillis() + span.TotalMilliseconds);
alarmMgr.SetExactAndAllowWhileIdle(AlarmType.RtcWakeup, schedule, pending);
}
}
}
准确设置闹钟。至于让一切持久化,我让服务变得有粘性,并将其设置为每次重置时重置所有警报。这是通过检查广播是否已经存在,然后将其删除并在存在时重新安排来完成的。
PendingIntent temp = PendingIntent.GetBroadcast(this, eventID, wake, PendingIntentFlags.NoCreate);
if (temp != null)
{
temp.Cancel();
}
这个和接收启动通知的广播接收器的组合使警报尽可能持久。