API 24上的AlarmManager函数但是API 28上没有

时间:2019-06-10 15:53:18

标签: android alarmmanager

我正在使用Android AlarmManager每隔5分钟启动一次事件。这在我的api 24手机上正常工作,但在我的api 28手机上无法正常工作。在api 28上运行时,电话dumpsys alarm显示警报正在响起,但从未调用过按其意图传递的JobIntentService

到目前为止,我已经尝试了各种设置警报的方法,例如setAndAllowWhileIdle没有任何效果。在api 28手机上运行dumpsys alarm表示单拍setAlarmWhileIdle熄灭,但没有再次熄灭。同样,setInexactRepeating也以经过的重复间隔发出声音。两者都不调用传递的JobIntentService

public class DataUploadService extends JobIntentService
    implements DataClientManager.OnDataChangedListener {

private static final String TAG = "DataUploadService";
private static void LOG(String msg) { Log.d(TAG,msg); }
private static void LOGE(String msg) { Log.e(TAG,msg); }

public static final int DELAY_PERIOD = 5;

public static void initialize(Context context) {

    //parse minutes to get exact time
    final Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(System.currentTimeMillis());
    calendar.add(Calendar.MINUTE,DELAY_PERIOD);

    DataUploadService.setAlarm(context,calendar.getTimeInMillis());

}

public static void setAlarm(Context context, long millis) {

    clearAlarm(context);

    AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);

    Intent intent = new Intent(context, DataUploadService.class);
    PendingIntent alarmIntent = PendingIntent.getService(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);

    alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, millis,
            DELAY_PERIOD * 60 * 1000, alarmIntent);

}

public static void clearAlarm(Context context) {
    AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);

    Intent intent = new Intent(context, DataUploadService.class);
    PendingIntent alarmIntent = PendingIntent.getService(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);

    alarmManager.cancel(alarmIntent);
}

@Override
protected void onHandleWork(Intent intent) {

    LOGE("Data Acquisition Service has been called");
    final Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(System.currentTimeMillis());
    LOG(calendar.getTime().toString());

}
}

在我的MainActivity中,我呼叫DataUploadService.initalize(this),此后我希望每隔5分钟在系统日志"Data Acquisition Service has been called"中看到一次。这在我的api 24手机上按需要发生,但在我的api 28手机上却没有发生。我发现文档中AlarmManager的api没有明显的区别。

更新

我发现set(int type, long triggerAtMillis, String tag, AlarmManager.OnAlarmListener listener, Handler targetHandler)可在我的api级别28设备上使用。空Handler和非空JobIntentService似乎都可以工作。这不能回答我关于DECLARE TYPE my_id_tab IS TABLE OF my_table.my_id%TYPE; my_ids my_id_tab; BEGIN UPDATE my_table SET another_id = NULL WHERE another_id IS NULL AND create_datetime BETWEEN '03-JUN-19' AND '05-JUN-19' RETURNING my_id BULK COLLECT INTO my_ids; COMMIT; END; 为何不再起作用但确实可以解决临时问题的问题。

1 个答案:

答案 0 :(得分:0)

我想问题是因为您正在计划警报并在服务到期时启动服务。

由于服务是后台任务,因此(从API26 +开始)它们现在受到了更多限制

所以,我看到了两种解决方案:

第一个解决方案

创建一个广播接收器(将意图添加到AndroidManifest.xml中)。因此,在5分钟后,该广播将收到该意图,该广播将通过以下方式启动服务:

AndroidManifest

<receiver
    android:name=".DataUploadBroadcast"
    android:exported="true"
    tools:ignore="ExportedReceiver">
    <intent-filter>
        <action android:name="MY_CUSTOM_ACTION" />
    </intent-filter>
</receiver>

BroadcastReceiver

public class DataUploadBroadcast extends BroadcastReceiver {

    public static final int DELAY_PERIOD = 5;

    public void onReceive(Context receivedContext, Intent intent) {
        if("MY_CUSTOM_ACTION".equals(intent.getAction() {
            DataUploadService.enqueueWork(context, new Intent(context, DataUploadService.class);
        }
    }

    private static void setAlarm(Context context, long millis) {
        clearAlarm(context);
        AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);

         // Note the class is different now
        Intent intent = new Intent(context, DataUploadBroadcast.class);

        // Set action
        intent.setAction("MY_CUSTOM_ACTION");

        // Note the getBroadcast
        PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, millis, DELAY_PERIOD * 60 * 1000, alarmIntent);
    }

    public static void initialize(Context context) {
        // call setAlarm
    }

    private static void clearAlarm(Context context) {
        // Clear the alarm
    }
}

DataUploadService

private static final int JOB_ID = 100;

public static void enqueueWork(Context context, Intent work) {
    // This is how you should start the job.. and not PendingIntent.getService(...)
    enqueueWork(context, DataUploadService.class, JOB_ID, work);
}

@Override
protected void onHandleWork(Intent intent) {
    LOGE("Data Acquisition Service has been called");
}

第二个解决方案

让服务在“活动”请求发送后立即启动。然后,在onHandleWork期间,您将服务休眠5分钟:

public class DataUploadService extends JobIntentService
    implements DataClientManager.OnDataChangedListener {

    public static final int DELAY_PERIOD = 5;
    private static final int JOB_ID = 100;

    public static void initialize(Context context) {
        enqueueWork(context, DataUploadService.class, JOB_ID, new Intent(context, DataUploadService.class));
    }

    @Override
    protected void onHandleWork(Intent intent) {
        try {
            Thread.sleep(DELAY_PERIOD * 60 * 1000);
            efectivellyExecuteWork()
        } catch (InterruptedException e) {
            LOGE("ERROR");
        }
}

private void efectivellyExecuteWork() {
    LOGE("Data Acquisition Service has been called");
    final Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(System.currentTimeMillis());
    LOG(calendar.getTime().toString());
}

在第二种解决方案中,我只是将线程休眠了5分钟。如果您需要更新该计时器,以防用户在活动到期之前打开活动,则可以添加一些逻辑。 例如,您可以存储带有日期的日历实例。这样,线程将休眠直到到达该日期为止。这样一来,您就可以在必要时更新日历日期(就像清除/重新创建活动一样);

类似的东西:

try {
    while(futureDate.getTimeInMillis() > Calendar.getInstance.getTimeInMillis()) {
        Thread.sleep(futureDate.getTimeInMillis() - Calendar.getInstance.getTimeInMillis());
    }
    efectivellyExecuteWork()
} catch (InterruptedException e) {
    LOGE("ERROR");
}