android - TimerTask 在服务中停止触发
问题描述
我需要有一个在 Android 中运行的服务,它每隔一段时间就会向数据库存储一个值。频率取决于用户的偏好,以及是否发生了其他事件,可能长达 30 秒或长达 30 分钟。
这不是对用户隐藏的东西,实际上用户可能应该知道它的运行。因此,我认为前台服务可能是最好的方法。
我有一个前台服务正在运行,有一个 TimerTask 计算它需要多久触发一次。该服务是“粘性的”,因此它应该一直存在,并且操作系统应该在一段时间后启动它的资源不足。
我的问题是当应用程序在后台运行一段时间后 TimerTask 似乎停止运行。
这是我的服务:
public class TimerService extends Service {
private static final String LOG_NAME = TimerService.class.getName();
private Timer timer;
private final Handler timerHandler = new Handler();
@Override
public void onCreate() {
super.onCreate();
Notification notification = new NotificationCompat.Builder(this, "MY_APP_CHANNEL_ID")
.setContentTitle("My Timer Service")
.setContentText("Background timer task")
.setSmallIcon(R.drawable.timer)
.build();
startForeground(1, notification);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
startTimer();
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
stopTimer();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void stopTimer() {
if (timer != null) {
timer.cancel();
timer = null;
}
}
private void startTimer() {
stopTimer();
timer = new Timer();
long frequency = // calculate frequency
long delay = // calculate delay
timer.scheduleAtFixedRate(new MyTimerTask(), delay, frequency);
}
private void saveToDatabase() {
// Save some stuff to the database...
if (some condition) {
// might need to reschedule timer delay and frequency.
startTimer();
}
}
private class MyTimerTask extends TimerTask {
@Override
public void run() {
timerHandler.post(new Runnable() {
@Override
public void run() {
onTimerFire();
}
});
}
private void onTimerFire() {
try {
saveToDatabase();
} catch (Exception e) {
Log.e(LOG_NAME, "Error in onTimerFire", e);
}
}
}
}
这应该工作吗?IE 我可以在前台服务中有一个简单的计时器,它会持续触发直到该服务停止?如果是这样,我的代码中有错误吗?
我选择了一个计时器来保持简单,我只需要一个计时器运行,我希望它能够轻松地重新安排。我确实意识到我可以尝试使用 Handler、ScheduledThreadPoolExecutor 甚至是 AlarmManager。我认为一个 AlarmManager 可能是矫枉过正,如果它正在发射大量资源会消耗资源。更不用说重新安排了。
解决方案
为什么它不会在后台运行?
它在后台运行。当设备处于睡眠状态时,它不会运行,因为 CPU 已断电。在 Android 中,“后台”仅表示“没有前台 UI”(活动、具有前台的服务Notification
)。
我需要有一个在 Android 中运行的服务,它每隔一段时间就会向数据库存储一个值。频率取决于用户的偏好,以及是否发生了其他事件,可能长达 30 秒或长达 30 分钟。
自 6.0 以来,您想要的东西在 Android 上并不实用。
我认为一个 AlarmManager 可能是矫枉过正,如果它正在发射大量资源会消耗资源。
那是真实的。但是,让现有代码工作的唯一方法是获取 partial WakeLock
,从而保持 CPU 永远运行。这将比现在的功率差几个数量级AlarmManager
。并且AlarmManager
已经够糟糕了,从 6.0 开始的每个 Android 版本都使得使用AlarmManager
(或JobScheduler
、或Timer
和唤醒锁)可靠地做任何事情变得越来越困难。
您将需要了解 Android 在后台处理方面的能力和不能力,然后相应地调整您的产品计划。这个主题对于 Stack Overflow 的回答来说太长了。
这是我去年就该主题发表的演示文稿中的一组幻灯片Space,其中考虑了 Android 8.0(用于前进到下一张幻灯片)。您可能还阅读:
我对 Android P DP2 的看法,尤其是“后台处理战争中的新功能”
这是我的一本书章节的预览,其中包含有关 Android 8.0 及其在“后台处理之战”中的阶段的部分
恕我直言,如今编写依赖于定期后台处理的应用程序是一项非常冒险的冒险。
推荐阅读
- octobercms - 十月CMS | 如何在php(ajax)中获取下拉值
- logback - 服务器 ip 在哨兵 logback 中显示为客户端 ip
- asp.net - Windows 身份验证在应用程序中失败,但在专用站点中成功
- python - 为 dask 指定仪表板端口
- java - 如何在java中使用softassertion拍摄快照
- sapui5 - SAPUI5:从 SAPUI5 中的另一个视图导航时,无法导航到特定的向导步骤
- html - 使用 Springboot 将复选框值插入 Mongodb
- ios - iOS13 临时位置权限
- angular - 应用程序状态未在单独的浏览器选项卡中更新
- rust - nom如何区分负号和负数?