首页 > 解决方案 > Xamarin.forms Android 后台进程中的意外警报触发

问题描述

我只是想获得多个倒计时计数器,当它分别达到 0 时,我想发出警报(用户在一个和下一个之间没有任何交互)。

例如,倒计时被编程为 5、4 和 7 分钟。如果是几秒钟,并且应用程序在屏幕开启或仅几秒钟的情况下工作没有问题,但只要几分钟,屏幕就会关闭并且手机进入打盹模式(我认为),结果时间是:5、6: 26 和 9:58(而不是 5,4 和 7)。

我已经阅读了很多这里讨论过的用户解决方案,但它对我不起作用。该手机运行Android v10。

使用 SetExactAndAllowWhileIdle 对警报进行编程的代码:

public void ProgAlarm(int nIntervalo) {
    var alarmIntent = new Intent(MainActivity.Instance, typeof(AlarmReceiver));
    alarmIntent.PutExtra("Contador", nIntervalo);
    var pending = PendingIntent.GetBroadcast(MainActivity.Instance, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);

    MainActivity.alarM.SetExactAndAllowWhileIdle(AlarmType.ElapsedRealtimeWakeup,
        SystemClock.ElapsedRealtime()+tiempos[nIntervalo]*1000, pending);
}

并触发事件以重新编程警报:

[BroadcastReceiver]
public class AlarmReceiver: BroadcastReceiver {
   public override void OnReceive(Context context, Intent intent) {
       DependencyService.Get<IVarios>().Beep();
       int actual=intent.GetIntExtra("Contador",-1);
       if (actual!=-1) DependencyService.Get<IVarios>().ProgAlarm(++actual);
    }
}

在警报之前,我尝试使用 PowerManager:

PowerManager pM = (PowerManager)GetSystemService(PowerService);
wakeLock=pM.NewWakeLock(WakeLockFlags.Partial, "CronoMultiple");
[...]
wakeLock.Acquire();
[...]
wakeLock.Release();

并带有标志:WakeLockFlags.AcquireCausesWakeup

但这仅在屏幕始终处于打开状态且带有 .Partial 标志时才有效,屏幕关闭并且应用程序停止并且计数器不起作用。在 PC 模拟器中它可以工作(即使使用 adb 命令),但不能在手机上工作。

任何不使用服务的解决方案?(我是 Xamarin.forms 的新手)。

标签: c#androidxamarin.forms

解决方案


这是一个简单的示例,它会每 1 分钟报警一次:

界面IVarios

public interface IVarios
{
    void ProgAlarm(int minute);
} 

MainActivity中,让它实现Ivarios

public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity,IVarios
{
   public void ProgAlarm(int minute)
    {
        Intent intent = new Intent(MainActivity.Instance, typeof(LongRunningService));
        intent.PutExtra("Contador", minute);
        MainActivity.Instance.StartService(intent);
    }
}

在 Android 项目中,创建LongRunningService

[Service]
class LongRunningService : Service
{

    int minutes;
    public override IBinder OnBind(Intent intent)
    {
        return null;
    }
    public override void OnCreate()
    {
        base.OnCreate();
    }

    [return: GeneratedEnum]
    public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
    {
       Android.Util.Log.Error("LongRunningService", "executed");
        AlarmManager manager = (AlarmManager)GetSystemService(AlarmService);
        int min = intent.GetIntExtra("Contador", -1);
        minutes = min != -1 ? min : minutes;
        int anHour = minutes * 60 * 1000;   // Number of milliseconds

        long triggerAtTime = SystemClock.ElapsedRealtime() + anHour; 

        Intent i = new Intent(this, typeof(AlarmReceiver));
        PendingIntent pi = PendingIntent.GetBroadcast(this, 0, i, PendingIntentFlags.UpdateCurrent);

        manager.SetExactAndAllowWhileIdle(AlarmType.ElapsedRealtimeWakeup, triggerAtTime, pi);
        return StartCommandResult.Sticky;
    }
}

在 Android 项目中,创建AlarmReceiver

[BroadcastReceiver(Enabled = true)]
[IntentFilter(new[] { Android.Content.Intent.ActionBootCompleted })]
class AlarmReceiver : BroadcastReceiver
{
    public override void OnReceive(Context context, Intent intent)
    {
        Intent i = new Intent(context, typeof(LongRunningService));
        context.StartService(i);
    }
}

然后你可以在你的页面中调用它:

 DependencyService.Get<IVarios>().ProgAlarm(1);

推荐阅读