当前位置: 首页 > 知识库问答 >
问题:

如何使一个周期性的背景工作(15分钟的周期性间隔)无限期运行在奥利奥和以后?

欧阳晗日
2023-03-14

使用AlarmManagerApi设置重复警报:

public static void setAlarm(final Context context) {
    final AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    if (manager != null) {
        manager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 0, ALARM_INTERVAL,
                getAlarmPendingIntent(context));
    }
}

其中getAlarmPendingIntent方法如下所示:

private static PendingIntent getAlarmPendingIntent(final Context context) {
        return PendingIntent.getBroadcast(context, REQUEST_CODE, new Intent(context, AlarmReceiver.class), PendingIntent.FLAG_UPDATE_CURRENT);
    }

设置一个BroadcastReciever来累加警报:它在前台启动一个服务来完成所需的后台工作

public class AlarmReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(final Context context, final Intent intent) {
        if (context == null || intent == null) {
            return;
        }

        if (intent.getAction() == null) {
            Intent monitorIntent = new Intent(context, TaskService.class);
            monitorIntent.putExtra(YourService.BATTERY_UPDATE, true);
            ContextCompat.startForegroundService(context, monitorIntent);
        }
    }

}
public class TaskService extends Service {
    private static final String CHANNEL_ID = "channel_01";
    private static final int NOTIFICATION_ID = 12345678;

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

    public void createNotificationChannel(){
        // create notification channel for notifications
        NotificationManager mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            CharSequence name = getString(R.string.app_name);
            NotificationChannel mChannel =
                    new NotificationChannel(CHANNEL_ID, name, NotificationManager.IMPORTANCE_DEFAULT);
            if (mNotificationManager != null) {
                mNotificationManager.createNotificationChannel(mChannel);
            }
        }
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        startForeground(NOTIFICATION_ID, getNotification());    
        BatteryCheckAsync batteryCheckAsync = new BatteryCheckAsync();
        batteryCheckAsync.execute();
        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    private Notification getNotification() {
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentText(text)
                .setContentTitle("fetching battery level")
                .setOngoing(true)
                .setPriority(Notification.PRIORITY_LOW)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setWhen(System.currentTimeMillis());

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            builder.setChannelId(CHANNEL_ID);
        }

        return builder.build();
    }


    private class BatteryCheckAsync extends AsyncTask<Void, Void, Void> {

        @Override
        protected Void doInBackground(Void... arg0) {
            IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
            Intent batteryStatus = YourService.this.registerReceiver(null, ifilter);
            int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
            int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
            Log.i("Battery Charge Level",String.valueOf((level / (float) scale)));
            return null;

        }

        protected void onPostExecute() {
            YourService.this.stopSelf();
        }
    }
}

BatteryCheckAsync任务从后台获取电池电量,并在日志中显示当前电池电量。

从https://developer.android.com/training/monitoring-device-state/doze-standby上的android文档中,我发现它记录了

标准的AlarmManager警报(包括setExact()和setWindow())被推迟到下一个维护窗口。

如果您需要设置在打瞌睡时触发的警报,请使用setAndAllowWhileIdle()或setExactAndAllowWhileIdle()。

public static void setAlarm(final Context context) {
        final AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        if (manager == null) {
            return;
        }

        int SDK_INT = Build.VERSION.SDK_INT;
        if (SDK_INT < Build.VERSION_CODES.KITKAT) {
            manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, ALARM_INTERVAL, getAlarmPendingIntent(context));
        } else if (SDK_INT < Build.VERSION_CODES.M) {
            manager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, ALARM_INTERVAL, getAlarmPendingIntent(context));
        } else {
            manager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, ALARM_INTERVAL, getAlarmPendingIntent(context));
        }
    }

在Android Oreo及以上版本中,有没有一个解决方案可以保证在不确定的时间内执行周期性的后台任务?我正在安装Android奥利奥或以上的OnePlus设备上测试它。

共有1个答案

张承颜
2023-03-14

尝试改变

public class AlarmReceiver extends WakefulBroadcastReceiver {
    //logic
}

还要更改警报管理器的事件alarmmanager.set(alarmmanager.rtc_wakeup,...)

因此,您将从doze模式唤醒设备并执行您的工作。

 类似资料:
  • 系统 cron 作业 系统 cron 作业不是使用 crontab 命令定义的,而是在一组配置文件中配置的。系统 cron 作业是在两个位置定义的:/etc/crontab 和 /etc/cron.d/*。安装 cron 作业的软件包应当通过在 /etc/cron.d/ 中放置文件才能执行安装操作,但是,管理员还可以使用此位置来更轻松地将相关作业分到单个文件中,或者使用配置管理系统推送作业。/et

  • 周期性的HttpJob任务的定义 是多次运行的job 采用Cron表达式进行定义运行规则 注意事项 最新版的hangfire已支持 6位数的Cron表达式(支持到秒级) 但是我在hangfire的dashbord扩展的Cron生成页面还不支持到秒级别(大家可以在google找可以生成6位的网站工具) 1. 进入hangfire的后台 点击 上侧栏【周期性作业】 如下图所示: 针对周期性作业 可以看

  • Ths是我的服务班 }

  • 有两种执行指令的机制。 单时钟周期实现 管道 在MIPS体系结构(摘自《计算机组织与设计》一书)中,教学分为5个阶段。 因此,在单时钟周期实现中,这意味着在一个时钟周期内,一条指令执行5个阶段。 例如,加载指令(有5个阶段)在一个时钟周期内执行。因此,在这一个时钟周期之后可以执行其他指令。让我们假设一个时钟周期是10秒。 现在,在流水线中,多条指令可以重叠。与上面示例中的一个时钟周期的时间相比,我

  • 执行周期性任务也是一样简单,您只需要编写一行代码: RecurringJob.AddOrUpdate(() => Console.Write("Easy!"), Cron.Daily); 此行在持久存储中创建一个新实体。 Hangfire Server中的一个特殊组件(请参阅 处理后台任务) 以分钟为间隔检查周期性任务,然后在队列中将其视作 fire-and-forget 任务。这样就可以照常跟踪