AlarmManager.SetRepeating 工作不正常

AlarmManager.SetRepeating not working properly

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

来自 MainActivity 的代码:

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

闹钟class:

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

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

[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.

当您在 activity 中调用 RegisterReceiver 时,会发生第二次注册。这会注册一个新的、唯一的 Alarm 实例来监听 com.company.BROADCAST.

的广播

您可以通过从 Alarm 中删除 [IntentFilter(new string[] {"com.company.BROADCAST"})] 属性或删除 activity 中的 RegisterReceiver 调用来修复 "alarm being called twice" 问题。


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

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

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

如果你想如此频繁地重复操作,请考虑使用定时器或 post 延迟处理程序:

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