AlarmManager.SetRepeating无法正常工作

时间:2016-03-06 18:29:49

标签: c# android xamarin android-alarms

我正试图通过AlarmManager定期调用一个线程。问题是,在给定的时间段后,OnReceive()被调用两次(为什么?)然后再也没有。我在这做错了什么?
我在API级别23上使用Xamarin(C#)for Android。

MainActivity的代码:

Alarm alarm = new Alarm ();
RegisterReceiver (alarm, new IntentFilter ("com.company.BROADCAST"));
alarm.SetAlarm(this);

警报类:

[BroadcastReceiver]
[IntentFilter(new string[] {"com.company.BROADCAST"})]
public class Alarm : BroadcastReceiver
{
    public override void OnReceive(Context c, Intent i)
    {
        Toast.MakeText (c, "hi", ToastLength.Short).Show ();
    }

    public void SetAlarm(Context context)
    {
        AlarmManager am = (AlarmManager)context.GetSystemService(Context.AlarmService);
        Intent i = new Intent("com.company.BROADCAST");
        PendingIntent pi = PendingIntent.GetBroadcast(context, 0, i, 0);
        am.SetRepeating(AlarmType.ElapsedRealtimeWakeup, SystemClock.ElapsedRealtime() + 1000, 1000 * 2, pi);
    }
}

1 个答案:

答案 0 :(得分:1)

OnReceive被调用两次,因为您不小心将闹钟注册了两次。我们将以下代码段添加到您的Alarm课程中:

[BroadcastReceiver]
[IntentFilter(new string[] {"com.company.BROADCAST"})]
public class Alarm : BroadcastReceiver
{

    public Alarm ()
        : base()
    {
        Console.WriteLine ("Alarm made: " + this.GetHashCode ());
    }

    public Alarm(System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
        : base(handle, transfer)
    {
        Console.WriteLine ("Alarm made: " + this.GetHashCode ());
    }

    // ...
}

如果我们运行应用程序,Alarm将为每个创建的实例注销一个唯一的哈希码。因此,启动应用程序并观察应用程序输出中发生的情况:

Alarm made: 123719217
...
Alarm made: 119997678

哇!我们有2个实例......那是怎么发生的?

属性[IntentFilter(new string[] {"com.company.BROADCAST"})]会为您的Alarm : BroadcastReceiver生成一个清单条目,使其自动收听com.company.BROADCAST的广播。 Xamarin文档有一个很好的解释here

当您在活动中致电RegisterReceiver时,会发生第二次注册。这会注册一个新的Alarm唯一实例来监听com.company.BROADCAST的广播。

你可以修复被叫两次的警报"通过从[IntentFilter(new string[] {"com.company.BROADCAST"})]移除Alarm属性或移除活动中的RegisterReceiver调用来解决此问题。

其次,2000毫秒对于AlarmManager的频率来说太小了。它会自动将其扩展到60秒以延长电池寿命。

如果您运行示例并使用logcat捕获系统输出,那么您将看到一条消息确认:

W/AlarmManager(  579): Suspiciously short interval 2000 millis; expanding to 60 seconds

如果您想如此频繁地重复操作,请考虑使用计时器或发布延迟处理程序:

// Frequent operation using .NET Timer.
System.Timers.Timer t = new System.Timers.Timer (1000);
t.AutoReset = true;
t.Elapsed += (object sender, System.Timers.ElapsedEventArgs e) => {
    t.Interval = 2000;
    RunOnUiThread (() => Toast.MakeText (this, "Hi", ToastLength.Short).Show ());
};
t.Start ();

// Frequent operation using Android.OS.Handler
handler = new Handler ();
Action callback = null;
callback = () => {
    //Do something after 100ms
    Toast.MakeText(this, "Hi", ToastLength.Short).Show();  
    handler.PostDelayed(callback, 2000);
};
handler.PostDelayed(callback, 1000);