JAVA/Android 笔记 定时/循环任务以及动画(Animator)

来源:互联网 发布:上海火速网络 编辑:程序博客网 时间:2024/06/06 14:24

定时任务/循环任务

在研究程序的时候,我经常会考虑一个问题,就是 :
如何有效率的执行一个定时任务

初学的时候,书上提到过一些这样的情况,然后会告诉我使用一些什么API来执行这样的任务。
1. 使用Thread.sleep(long time)。这个很好理解,就是新开一个线程,然后让这个线程sleep一段时间,再执行,这就是最好理解的定时执行。
2. 使用Timer.schedule(),然后置入一个Timertask。Timer是JAVA里面专门用来执行定时任务的API,Timertask实现了runnable接口,定时器会在设定的时间段内执行。
3. 使用ScheduledExecutorService 具体使用方法例如:

ScheduledExecutorService service = Executors                    .newSingleThreadScheduledExecutor();service.scheduleAtFixedRate(runnable, 0, 1, TimeUnit.SECONDS);  

与之前的两个方法相比,这个方法是使用的线程池,而timer是创建一个单线程来执行。所以这个效率更好。
(我没有使用过这个方法,这个我也是才知道的。)

参考:java实现定时任务的三种方法

原理探索

一般情况使用这3种方法就可以了。事实上还有一些java第三方库,可以提供一些有效的其他方法来实现这些任务。但是:
只会用“库”算不得什么本事。
我需要了解一些原理。这个到底是怎么执行的,官方API是如何运行的。
以及如何自己编写一个类似的程序/库

实际上如果探究底层代码的话,从android的代码里面可以看到很多native字样,也就是说,这些是在底层用C语言写的,看不到。那就不管这些,最起码研究下可以看到的内容。

Timer类

首先,我发现Android里面的Timer和JAVA SE里面的有些不同。(当然也找到了一些其他地方的不同。)
但是我认为应该区别不大。

Android studio里面可以很方便的查看官方API 函数的代码,所以我查看的是Android里面的代码。

  1. 在Timer创建的时候,会创建一个线程TimerThread。线程立即开始运行。这个线程是扩展的Thread的自建类,里面有一个方法叫 mainloop,里面是一个while(true)的循环,退出条件在内部设置。在TimerThread启动的时候,就会开始运行mainloop
  2. 里面还有一个TaskQueue,保存的是一个TimerTask的数组,在mainloop里面会挨个运行这个数组里面的任务。在循环里面会对queue加锁(synchronized)。
  3. 因为是定时任务,所以在TimerTask里面会保存这个任务的运行时间,以及循环间隔时间(如果有的话)。在上面将的mainloop里面,每次循环会查找当前taskQueue里面的任务,对比timertask的运行时间是否是当前时间。如果是,就运行,如果不是就等待下一次循环。
  4. mainloop的退出条件是queue.isEmpty()。每次循环的时候都会检查。如果定时任务是单次的,那么运行以后就会被移除taskqueue,如果是循环的,就会在执行以后移动到queue的末尾。
  5. 因为这个是使用工作线程,所以为了避免造成资源浪费,设置了一个等待条件。如果queue.isEmpty()并且newTasksMayBeScheduled=true,就执行queue.wait()。这个方法告诉程序把当前queue对象锁挂起,不再占用cpu资源。直到有新任务进入,会调用queue.notify(),告诉queue对象的锁可以开始运行了。

基本上Timer的原理就是这些,代码比较短,所以容易读懂。
参考:Java线程间的通信方式详解

Animator

Android有一个很好用的动画组件叫ValueAnimator,可以设置起始值/目标值,duration等参数,就可以很平滑的在设置的起始值到目标值之间变化。为了实现动作,也需要设置一个listener。

我想研究下这个类到底是用什么方法实现定时任务的。说实在的,其他的东西都好解决,无非就是考虑周到一点,写的全面一点,各种情况都照顾到,功能就能实现,我是想探索一下到底用什么办法能最有效的实现定时功能。(探索的是底层实现,而不是普通实现,如果要简单的实现定时功能,Android和JAVA给我们提供了好几种方法,timer,handler,等等)

我打开ValueAnimator的源码一看,果然很复杂,我一时间甚至都找不到怎么循环的。总不能就进行了一帧就结束了吧。

在这之前我还查看了Handler,这个类用postDelay实现了定时功能。我往伸出了找,果然发现了native方法,果然还是用native来实现了。看来探索到此为止了。(C语言几乎忘光了,正准备从头开始复习一下)

那么ValueAnimator是怎么实现定时呢?我在层层深入加网上查询的帮助下发现,原来是借助handler实现了,也就是说,先计算出中间的关键帧的时间/值,然后往handler里面sendMessageAtTime,顾名思义,也就是在关键帧的时间点发送信息,handler接收到以后就处理,也就是运行到关键帧的值位置。
看来直接使用handler是比较有效率的做法。

参考:Animator
参考:Handler

0 0