Xamarin Android:在特定时间重新打开应用程序

时间:2017-01-13 19:00:01

标签: c# android xamarin.android broadcastreceiver alarmmanager

我正在尝试在Xamarin中创建一个闹钟类型的应用程序,我现在正在努力让应用程序在特定时间打开备份,无论如何(不包括重启我知道)那就是onbootcompleted)但是当我现在关闭应用程序时,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);
        }

2 个答案:

答案 0 :(得分:1)

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);

答案 1 :(得分:0)

最终,在玩了几周之后,我终于发现了一种可靠的方式来发出警报,无论如何。总的来说,有很多关于这个过程的文档,但我发现其中很多都不是在一个地方。

所以这就是我所做的:

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();
}

这个和获得启动通知的广播接收器的组合使警报尽可能持久。