我正在创建一个按时间间隔执行操作的应用。我可以在更新之间等待的绝对最长时间是30秒,在0和0之间的任何东西都可以接受,但我更喜欢15秒以获得良好的测量。然而,它并不像听起来那么容易。我尝试了4种方法,由于种种原因,所有方法都是不可接受的。
请记住Service
中出现这些问题,当此代码在Activity
中运行时,它运行正常。我还注意到,当手机插入我的电脑进行调试时,解决方案3运行完全正常,直到我将其拔出。我检查了我的电池设置,没有省电模式或其他类似的东西,这可能是原因。
1. IntentService
做事,然后在15秒内重新安排。不幸的是,当报警准确无误时,AlarmManager.setExact()完全不可靠,正如我在这个风滚草中描述的那样:Android Alarm not triggering at exact time
2.具有Thread
的地面服务。在那个帖子中我做了我的东西然后sleep()
15秒。事实证明这种方法比以前更糟糕了,该线程在适当的时间之后被唤醒了5分钟。
3.然后我尝试使用Timer
(建议使用geokavel)并使用scheduleAtFixedRate
和schedule
安排工作,但工作大约在15-45秒内完成,这使得间隔为1分钟而不是15秒。
4.我想到达到这个目的的最后一种方法是不从上方睡在前台服务中的Thread
。相反,我比较时间:
public void run(){
nextTime = System.currentTimeMillis() + sleep;
while (true){
if (System.currentTimeMillis() >= nextTime) {
nextTime = System.currentTimeMillis() + sleep;
//do stuff
}
}
}
除了一个主要的缺点外,这种方法就像魅力一样 - 它一直使用20-25%的CPU。
所以我的问题是,是否有一种方法可以使上述解决方案正常工作(没有不可接受的缺点)?如果没有,我错过了更好的方式吗?如果需要,请随时询问更多细节。
编辑:请求的run()代码:
public void run(){
try {
if (Thread.currentThread().isInterrupted()){
throw new InterruptedException();
}
NetworkInfo info = cm.getActiveNetworkInfo();
if (info == null) {
throw new UnknownHostException();
}
if (info.getType() == ConnectivityManager.TYPE_MOBILE) {
Log.i(TAG, "Won't use mobile connection");
throw new UnknownHostException();
} else {
internetRestored();
st.updateData();
}
} catch (MalformedURLException | UnknownHostException e) {
internetFailed();
Log.e(TAG, "No internet connection, cant log");
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
Log.i(TAG, "Thread iterrupted");
}
}
答案 0 :(得分:0)
您定位/编译哪些API?
编辑:查看处理程序:
https://developer.android.com/reference/android/os/Handler.html
Handler有两个主要用途:(1)安排消息和 runnables将在未来的某个点上执行; (2)至 将要在不同于您自己的线程上执行的操作排入队列。 ... 发布或发送到处理程序时,您可以在消息队列准备好后立即允许处理该项目,或者在处理之前指定延迟或者处理它的绝对时间。后两者允许您实现超时,滴答和其他基于时间的行为。
我没有看到关于具体时间的任何警告,所以这可能是一个很好的镜头。
一些有趣的文档:
https://developer.android.com/reference/android/app/AlarmManager.html
来自Alarm Manager的更多信息:否则,警报将被设置为应用程序调用setRepeating(int,long,long,PendingIntent)。从API 19开始,所有重复警报都将是不精确的,并且无论其规定的重复间隔如何,都可以与其他警报进行批处理。
注意:从API 19(KITKAT)开始,警报传递是不准确的:操作系统 将移动警报以最小化唤醒和电池使用。那里 是支持需要严格交付的应用程序的新API 担保;请参阅setWindow(int,long,long,PendingIntent)和 setExact(int,long,PendingIntent)。应用程序 targetSdkVersion早于API 19将继续看到 以前的行为,其中所有警报都在何时传递 请求。
https://developer.android.com/reference/java/lang/Thread.html
使发送此消息的线程休眠给定的 时间间隔(以毫秒和纳秒为单位)。该 不保证精度 - 线程可能睡眠多于或少于 请求。
计时器:
此类不提供有关任务调度的实时性质的保证。
的ScheduledThreadPoolExecutor
延迟任务在启用之前执行,但没有任何执行 关于何时启用后,他们会实时保证 开始。计划完成相同执行时间的任务是 以先进先出(FIFO)提交顺序启用。
一些想法:
根据我所见,您最好的选择是降低目标API <&lt; 19并使用Alarm Manager。
如果这不起作用,我的下一个最佳选项是thread.sleep(),同时使用Thread.setPriority()将线程执行优先级设置为尽可能高;
如果不这样做,我会研究减少实时需求的方法 - 事实上,android处理处理器时间的方式很复杂,而且它并不是真正的实时系统。
如果您真的需要非常准确的计时,您可以探索C并尝试在AudioFastPath中执行您的代码,这会使您在处理器时间内尽可能保持规律性。多数民众赞成可能比杀人更有害。
答案 1 :(得分:-1)
钽沓! https://developer.android.com/reference/java/util/Timer.html
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
//code to run
}
},initial_delay,period);
答案 2 :(得分:-1)
Handler minuteHandler = new Handler();
minuteHandler.postDelayed(runnable, 60000);
final Runnable runnable = new Runnable() {
@Override
public void run() {
// your runnable code
minuteHandler.removeCallbacks(runnable);
minuteHandler.postDelayed(runnable, 60000);
}
};
答案 3 :(得分:-2)
如果Timers真的不适合你,那么最基本的实现就是这样的。您无需为此设置新服务:
$("#timepicker").kendoTimePicker({
dates: [
new Date(2000, 10, 10, 10, 0, 0),
new Date(2000, 10, 10, 10, 30, 0)
] //the drop-down list will consist only two entries - "10:00 AM" and "10:30 AM"
});
除非你在while循环中放入一个变量,或者添加一些条件和/或break语句,否则这将永远存在;