不使用手机时,AlarmManager重复报警随机丢失 [英] AlarmManager repeating alarm missing randomly when phone is not in use

查看:65
本文介绍了不使用手机时,AlarmManager重复报警随机丢失的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我每隔30分钟调用一次后台 Service 以读取当前位置的经度/纬度,并通过POST API将其发送到服务器。

I am calling a background Service at interval of 30 min to read the latitude/longitude of current location and sending it to server by POST API .

我正在使用 AlarmManager 类的 setRepeating()方法来安排每个警报30分钟。但是有时警报会丢失,并且不会调用服务。为了监视是否每30分钟调用一次警报,我在sdcard中生成了Log.txt文件。对于每次称为当前条目的警报,都会将其记录在Log.txt文件中。但是在将4到5个设备的Log.txt文件进行比较之后,我注意到对于某些设备,警报未调用 UserTrackingReceiver.java onCreate()方法/ code>(后台服务)。下面提到的完整代码块。

I am using setRepeating() method of AlarmManager class to schedule alarm every 30 minutes. But some times the alarm is getting missed and service is not called. To monitor if alarm gets called or not in every 30 min I have generated Log.txt file in the sdcard. For every time alarm called the entry for the current time will be written in the Log.txt file. But after comparing 4 to 5 devices Log.txt files I noticed that for some of devices alarm is not calling onCreate() method of UserTrackingReceiver.java (Background service) . Full code chunks mentioned below.

当应用启动时,调用了 registerUserTrackingReceiver()方法,如下所示:

When app start registerUserTrackingReceiver() method has been call which is below:

public static void registerUserTrackingReceiver(Context context) {
        try {
            Intent intent = new Intent(context, UserTrackingReceiver.class);

            boolean alarmUp = (PendingIntent.getService(context, 1001, intent, PendingIntent.FLAG_NO_CREATE) == null);

            if (alarmUp) {
                Calendar calendar = Calendar.getInstance();

                if (calendar.get(Calendar.MINUTE) > 0 && calendar.get(Calendar.MINUTE) <= 30) {
                    calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY));
                    calendar.set(Calendar.MINUTE, 30);
                    calendar.set(Calendar.SECOND, 0);
                } else if (calendar.get(Calendar.MINUTE) > 30) {
                    if (calendar.get(Calendar.HOUR_OF_DAY) == 23) {
                        calendar.set(Calendar.HOUR_OF_DAY, 0);
                    } else {
                        calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) + 1);
                    }
                    calendar.set(Calendar.MINUTE, 0);
                    calendar.set(Calendar.SECOND, 0);
                } else {
                    calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY));
                    calendar.set(Calendar.MINUTE, 0);
                    calendar.set(Calendar.SECOND, 0);
                }

                PendingIntent sender = PendingIntent.getService(context, 1001, intent, 0);
                AlarmManager alarmManager = (AlarmManager) context.getSystemService(context.ALARM_SERVICE);
                alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
                        AlarmManager.INTERVAL_HALF_HOUR, sender);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
}

UserTrackingReceiver.java 是以下:

public class UserTrackingReceiver extends Service
        implements LocationListener,
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener {

    @Override
    public void onCreate() {
        super.onCreate();

        Calendar calendar = Calendar.getInstance();
        Util.appendLog("Tracking Alarm Called on: " + calendar.get(Calendar.HOUR_OF_DAY) + " : " + calendar.get(Calendar.MINUTE) + " : " + calendar.get(Calendar.SECOND));
        stopSelf();
    }
}

Util.java 中有下面的 appendLog()方法:

public static void appendLog(String text) {

        String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath();

        File logFile = new File(baseDir + "/" + Constant.AppNameSuper + "/log.txt");
        if (!logFile.exists()) {
            try {
                logFile.createNewFile();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        try {
            //BufferedWriter for performance, true to set append to file flag
            BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true));
            buf.append(text);
            buf.newLine();
            buf.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
}

如果按照上述代码每30分钟发出一次警报,应该写在SDCARD中的Log.txt文件中。但是问题在于它无法每30分钟写入一次日志文件,这意味着缺少警报。根据两天的阅读时间,我注意到当用户连续使用手机时,白天并不会丢失警报,但是在不使用手机的夜晚却会丢失警报。

If alarm called every 30 min as per above code it should be written in Log.txt file in SDCARD. But the issue is it cannot write log file every 30 min that means alarm is missing. As per taking reading for two days I have noticed that alarm is not missing in day time as user continuously use their phone but it is missed in night when phone is not in use.

具有不同设备的输出日志文件如下:

设备A Log.txt



  • 跟踪警报已调用:0:0:31(从12:00晚开始)

  • 跟踪警报已调用:1:10:27

  • 跟踪警报已调用:3:5:25

  • 跟踪警报已调用:6:55:31

  • 跟踪警报已调用:7:0:6

  • 跟踪警报已调用:7:30:0 0

  • 跟踪警报调用:8:0:6

  • 跟踪警报调用:8:30:0 0

  • 调用的跟踪警报:9:0:6

  • 调用的跟踪警报:9:30:0

  • 调用的跟踪警报:10: 0:0

  • Tracking Alarm Called on: 0 : 0 : 31(Start From 12:00 Night)
  • Tracking Alarm Called on: 1 : 10 : 27
  • Tracking Alarm Called on: 3 : 5 : 25
  • Tracking Alarm Called on: 6 : 55 : 31
  • Tracking Alarm Called on: 7 : 0 : 6
  • Tracking Alarm Called on: 7 : 30 : 0
  • Tracking Alarm Called on: 8 : 0 : 6
  • Tracking Alarm Called on: 8 : 30 : 0
  • Tracking Alarm Called on: 9 : 0 : 6
  • Tracking Alarm Called on: 9 : 30 : 0
  • Tracking Alarm Called on: 10 : 0 : 0

设备B Log.txt



  • 跟踪警报呼叫:0:0:27(从12:00晚上开始)

  • 跟踪警报呼叫:0:0:30:1

  • 跟踪警报调用时间:1:0:1

  • 跟踪警报调用时间:1:30:2

  • 跟踪警报事件调用:2:0:1

  • 跟踪警报已调用:2:30:1

  • 跟踪警报已调用:3:0:1

  • 跟踪警报已调用:3:30:1

  • 跟踪警报已调用:4:0:1

  • 跟踪警报已调用: 4:30:29

  • 跟踪警报已调用:5:0:1

  • 跟踪警报已调用:5:30:2

  • 跟踪警报已调用:6:0:30

  • 跟踪警报已调用:6:30:1

  • 跟踪警报已调用:7:0:1

  • 跟踪警报已调用:7:30:1

  • 跟踪警报已调用:8:0 :1

  • 跟踪警报已调用:8:30:1

  • 跟踪警报已调用:9:0:32

  • 跟踪调用警报:9:30:1

  • Tracking Alarm Called on: 0 : 0 : 27(Start From 12:00 Night)
  • Tracking Alarm Called on: 0 : 30 : 1
  • Tracking Alarm Called on: 1 : 0 : 1
  • Tracking Alarm Called on: 1 : 30 : 2
  • Tracking Alarm Called on: 2 : 0 : 1
  • Tracking Alarm Called on: 2 : 30 : 1
  • Tracking Alarm Called on: 3 : 0 : 1
  • Tracking Alarm Called on: 3 : 30 : 1
  • Tracking Alarm Called on: 4 : 0 : 1
  • Tracking Alarm Called on: 4 : 30 : 29
  • Tracking Alarm Called on: 5 : 0 : 1
  • Tracking Alarm Called on: 5 : 30 : 2
  • Tracking Alarm Called on: 6 : 0 : 30
  • Tracking Alarm Called on: 6 : 30 : 1
  • Tracking Alarm Called on: 7 : 0 : 1
  • Tracking Alarm Called on: 7 : 30 : 1
  • Tracking Alarm Called on: 8 : 0 : 1
  • Tracking Alarm Called on: 8 : 30 : 1
  • Tracking Alarm Called on: 9 : 0 : 32
  • Tracking Alarm Called on: 9 : 30 : 1

设备C Log.txt



  • 跟踪警报已调用:0:0:7(从12:00晚开始)

  • 跟踪警报已调用:0:30:3

  • 跟踪警报已调用:1:0:6

  • 跟踪警报已调用:1:30:1

  • 跟踪警报已调用:2:0:32

  • 跟踪警报已调用:2 :30:3

  • 跟踪警报已调用:3:1:50

  • 跟踪警报已调用:3:30:5

  • 跟踪警报已调用:4:1:58

  • 跟踪警报已调用:4:31:14

  • 跟踪调用警报:5:0:1

  • 跟踪警报已调用:5:30:1

  • 跟踪警报已调用:6:2: 1

  • 调用的跟踪警报:6:30:1

  • 调用的跟踪警报:7:0:1

  • 调用的跟踪警报:7: 30:1

  • 跟踪警报已调用:8:0:1

  • 跟踪警报已调用:8:30:4

  • 跟踪警报已调用:9:1:44

  • 跟踪警报已调用:9:30:1

  • Tracking Alarm Called on: 0 : 0 : 7(Start From 12:00 Night)
  • Tracking Alarm Called on: 0 : 30 : 3
  • Tracking Alarm Called on: 1 : 0 : 6
  • Tracking Alarm Called on: 1 : 30 : 1
  • Tracking Alarm Called on: 2 : 0 : 32
  • Tracking Alarm Called on: 2 : 30 : 3
  • Tracking Alarm Called on: 3 : 1 : 50
  • Tracking Alarm Called on: 3 : 30 : 5
  • Tracking Alarm Called on: 4 : 1 : 58
  • Tracking Alarm Called on: 4 : 31 : 14
  • Tracking Alarm Called on: 5 : 0 : 1
  • Tracking Alarm Called on: 5 : 30 : 1
  • Tracking Alarm Called on: 6 : 2 : 1
  • Tracking Alarm Called on: 6 : 30 : 1
  • Tracking Alarm Called on: 7 : 0 : 1
  • Tracking Alarm Called on: 7 : 30 : 1
  • Tracking Alarm Called on: 8 : 0 : 1
  • Tracking Alarm Called on: 8 : 30 : 4
  • Tracking Alarm Called on: 9 : 1 : 44
  • Tracking Alarm Called on: 9 : 30 : 1

设备D Log.txt



  • 跟踪警报的调用时间:0:1:25(从12:00晚开始)

  • 跟踪警报的调用时间:0:30:0 0

  • 跟踪警报已调用:1:31:41

  • 跟踪警报已调用:2:39:52

  • 调用的跟踪警报:3:0:25

  • 调用的跟踪警报:3:30:58

  • 调用的跟踪警报:4: 0:25

  • 跟踪警报已调用:4:30:56

  • 跟踪警报已调用:5:30:51

  • Trac king警报已调用:7:18:55

  • 跟踪警报已调用:7:30:0

  • 跟踪警报已调用:8:0 :25

  • 跟踪警报已调用:8:30:43

  • 跟踪警报已调用:9:0:3

  • 跟踪警报已调用:9:30:25

  • 跟踪警报已调用:10:0:25

  • 跟踪警报已调用on:10:3​​0:4

  • 跟踪警报已调用:11:1:52

  • 跟踪警报已调用:11:30:27

  • 跟踪警报的调用时间:12:1:6⁠⁠⁠⁠

  • Tracking Alarm Called on: 0 : 1 : 25(Start From 12:00 Night)
  • Tracking Alarm Called on: 0 : 30 : 0
  • Tracking Alarm Called on: 1 : 31 : 41
  • Tracking Alarm Called on: 2 : 39 : 52
  • Tracking Alarm Called on: 3 : 0 : 25
  • Tracking Alarm Called on: 3 : 30 : 58
  • Tracking Alarm Called on: 4 : 0 : 25
  • Tracking Alarm Called on: 4 : 30 : 56
  • Tracking Alarm Called on: 5 : 30 : 51
  • Tracking Alarm Called on: 7 : 18 : 55
  • Tracking Alarm Called on: 7 : 30 : 0
  • Tracking Alarm Called on: 8 : 0 : 25
  • Tracking Alarm Called on: 8 : 30 : 43
  • Tracking Alarm Called on: 9 : 0 : 3
  • Tracking Alarm Called on: 9 : 30 : 25
  • Tracking Alarm Called on: 10 : 0 : 25
  • Tracking Alarm Called on: 10 : 30 : 4
  • Tracking Alarm Called on: 11 : 1 : 52
  • Tracking Alarm Called on: 11 : 30 : 27
  • Tracking Alarm Called on: 12 : 1 : 6⁠⁠⁠⁠


推荐答案

问题可能是您的 PendingIntent 调用了服务 。设备可以在您的服务完成(甚至开始执行)之前重新进入睡眠状态。

The problem might be your PendingIntent calling a Service. The device can go back to sleep before your Service finishes (or even starts) execution.

我建议您改为使用 BroadcastReceiver (因为在 onReceive()期间保证了 WakeLock )。

I'd suggest you to use a BroadcastReceiver instead (since a WakeLock is guaranteed during onReceive()).

onReceive()中获取 WakeLock ,从此处启动服务,然后从 Service释放 WakeLock (如果适用)。

Acquire a WakeLock in onReceive(), start your Service from there and release the WakeLock from the Service, when appropriate.

为简化此过程,您可以使用 WakefulBroadcastReceiver 辅助类:

To simplify this process you can use the WakefulBroadcastReceiver helper class:


  1. 调用 PendingIntent.getBroadcast()而不是 PendingIntent.getService()

  2. 通过调用 onReceive()启动 IntentService code> WakefulBroadcastReceiver.startWakefulService()

  3. onHandleIntent()中进行处理,然后调用 WakefulBroadcastReceiver.completeWakefulIntent()完成后。

  1. Call PendingIntent.getBroadcast() instead of PendingIntent.getService().
  2. Start an IntentService from onReceive() by calling WakefulBroadcastReceiver.startWakefulService().
  3. Do your stuff in onHandleIntent() and call WakefulBroadcastReceiver.completeWakefulIntent() when finished.

例如,一个 BroadcastReceiver 开始唤醒 Service

public class ExampleReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent wakefulServiceIntent = new Intent(context,
            ExampleWakefulService.class);

        WakefulBroadcastReceiver.startWakefulService(context,
            wakefulServiceIntent);
    }
}

服务

public class ExampleWakefulService extends IntentService {

    private static final String NAME = "com.example.ExampleWakefulService";

    public ExampleWakefulService() {
        super(NAME);
    }

    @Override
    protected void onHandleIntent(Intent intent) {

        // doing stuff

        WakefulBroadcastReceiver.completeWakefulIntent(intent);
    }
}

另外,请查看这篇文章

API级别23 + 上,您必须处理

文档


为了帮助安排警报,Android 6.0(API级别23)引入了
两个新的 AlarmManager 方法: setAndAllowWhileIdle()
setExactAndAllowWhileIdle()。使用这些方法,您可以设置警报
,即使设备处于打ze状态也将触发。

To help with scheduling alarms, Android 6.0 (API level 23) introduces two new AlarmManager methods: setAndAllowWhileIdle() and setExactAndAllowWhileIdle(). With these methods, you can set alarms that will fire even if the device is in Doze.

不幸的是,没有 setRepeating()的替代方法,因此您有两个选择:

Unfortunately there is no alternative for setRepeating(), so you have two choices:


  • 设置精确警报(根据设备的API级别使用适当的方法,请查看 此答案 以了解一个示例),并在每次触发时重新安排它们的时间。

  • 将您的应用列入白名单(由于Google严格的修订政策,因此不推荐使用)。

  • Set exact alarms (using the appropriate method depending on the API level of the device, check out this answer for an example) and reschedule them every time they fire.
  • Whitelist your app (not recommended because of the strict revision policy of Google).

这篇关于不使用手机时,AlarmManager重复报警随机丢失的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆