当前位置: 代码迷 >> 综合 >> Android 定时器的实现方式(TimerTask、Handler)及 Handler使用解析
  详细解决方案

Android 定时器的实现方式(TimerTask、Handler)及 Handler使用解析

热度:12   发布时间:2024-01-10 08:08:45.0

转自  二一点    点击打开链接


一、Handler的定义:主要接受子线程发送的数据, 并用此数据配合主线程更新UI。对于线程的控制,使用Handler可以对运行在不同线程中的多个任务进行排队,并使用Message和Runnable对象安排这些任务。在javadoc中,对Handler是这样解释的:Handler可以发送和处理消息对象或Runnable对象,这些消息对象和Runnable对象与一个线程相关联。每个Handler的实例都关联了一个线程和线程的消息队列。当创建了一个Handler对象时,一个线程或消息队列同时也被创建,该Handler对象将发送和处理这些消息或Runnable对象。
解释: 当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件,进行事件分发, 比如说, 你要是点击一个 Button ,Android会分发事件到Button上,来响应你的操作。如果此时需要一个耗时的操作,例如: 联网读取数据,或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,如果你放在主线程中的话,界面会出现假死现象, 如果5秒钟还没有完成的话,会收到Android系统的一个错误提示"强制关闭"。这个时候我们需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,Android主线程是线程不安全的,也就是说,更新UI只能在主线程中更新,子线程中操作是危险的。这个时候,Handler就出现了来解决这个复杂的问题。由于Handler运行在主线程中(UI线程中),  它与子线程可以通过Message对象来传递数据, 这个时候,Handler就承担着接收子线程传过来的(子线程用sendMessage()方法传递)Message对象,(里面包含数据)  , 把这些消息放入主线程队列中,配合主线程进行更新UI。

二、下面有几种对Handler对象的构造方法需要了解一下:
a、如果new一个无参构造函数的Handler对象,那么这个Handler将自动与当前运行线程相关联,也就是说这个Handler将与当前运行的线程使用同一个消息队列,并且可以处理该队列中的消息。
private Handler handler = new Handler();
b、如果new一个带参构造函数的Handler对象,那么这个Handler对象将与参数所表示的Looper相关联。注意:此时线程类应该是一个特殊类HandlerThread类,一个Looper类的Thread类,它继承自Thread类。
c、如果需要Handler对象去处理消息,那么就要重载Handler类的handleMessage函数。

三、Handler一些特点
handler可以分发Message对象和Runnable对象到主线程中, 每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程)。
它有两个作用: (1)、安排消息或Runnable在某个主线程中某个地方执行;(2)安排一个动作在不同的线程中执行。
        Handler中分发消息的一些方法
        post(Runnable)
        postAtTime(Runnable,long)
        postDelayed(Runnable long)
        sendEmptyMessage(int)
        sendMessage(Message)
        sendMessageAtTime(Message,long)
        sendMessageDelayed(Message,long)
        以上post类方法允许你排列一个Runnable对象到主线程队列中,sendMessage类方法, 允许你安排一个带数据的Message对象到队列中,等待更新。
要更改UI界面内容只能在主线程里面进行,下面是一个实现在Android中,动态更改UI界面的内容:先启动一个线程timer,此线程负责对UI进行动态更改的具体操作,此外,再定义一个线程来负责主线程和timer线程的通信,此线程就是Handler!它是Runnable和Activity交互的桥梁。

四、定时器实现方法一

1、在MainActivity中定义操作Title具体实现

[java]  view plain copy
print ?
  1. private int title = 0;  
  2. protected void updateTitle() {  
  3.     setTitle("welcome to Livingstone's blog" + title);// MainActivity中更新Title方法  
  4.     title++;  
  5. }  
2、在MainActivity中定义一个Handler,用于更新Title

[java]  view plain copy
print ?
  1. private Handler changeTitleHandler = new Handler() {  
  2.     @Override  
  3.     public void handleMessage(Message msg) {  
  4.         switch (msg.what) {  
  5.         case 1:  
  6.             updateTitle();  
  7.             break;  
  8.         }  
  9.     }  
  10. };  
3、在MainActivity中定义一个TimerTask类型内部类,此Task继承自Runnable

[java]  view plain copy
print ?
  1. private class Mytack extends TimerTask { // public abstract class TimerTask implements Runnable{}  
  2.     @Override  
  3.     public void run() {  
  4.         Message msg = new Message();  
  5.         msg.what = 1;  
  6.         changeTitleHandler.sendMessage(msg);  
  7.     }  
  8. }  
4、在MainActivity的onCreate方法中添加一个定时器

[java]  view plain copy
print ?
  1. Timer timer = new Timer();  
  2. timer.scheduleAtFixedRate(new Mytack(), 15000);  
  3. //Timer.scheduleAtFixedRate(TimerTask task, long delay, long period)  


五、使用handler自带方法实现定时器
public final boolean postDelayed(Runnable r, long delayMillis)
从当前时间开始延迟delayMillis时间后执行Runnable,只执行一次。

[java]  view plain copy
print ?
  1. runnable = new SendDataRunable();  
  2. handler.postDelayed(runnable, send_message_interval);  
SendDataRunable线程内部实现

[java]  view plain copy
print ?
  1. public class SendDataRunable implements Runnable{  
  2.     public void run() {  
  3.         // handler自带方法实现定时器  
  4.         try {   
  5.             if (context!=null) {  
  6.                 long currenttime = System.currentTimeMillis();  
  7.                 //定时器间隔  
  8.                 handler.postDelayed(this, send_message_interval);  
  9.             }  
  10.         }  
  11.     }  
  12. }  


六、Handler的使用场合:
1、 to schedule messages and runnables to be executed as some point in the future;
安排messages和runnables在将来的某个时间点执行。
2、 to enqueue an action to be performed on a different thread than your own.
将action入队以备在一个不同的线程中执行。即可以实现线程间通信。比如当你创建子线程时,你可以在你的子线程中拿到主线程中创建的Handler对象,就可以通过该对象向父线程的消息队列发送消息了。由于Android要求在UI线程中更新界面,因此,可以通过该方法在其它线程中更新界面。
1)、创建Handler对象(此处创建于主线程中便于更新UI)。
2)、构建Runnable对象,在Runnable中更新界面。
3)、在子线程的run方法中向UI线程post,runnable对象来更新UI,Handler.post(Runnable runa)。

七、Handler对Activity finish影响:
在开发的过程中碰到一个棘手的问题,调用Activity.finish方法 Acitivity没有执行生命周期的ondestory方法,后面查找半天是因为有一个handler成员,因为它有一个delay消息没有处理,调用Activity.finish,Activity不会马上destory,所以记得在Ativity finish前清理一下handle中的未处理的消息,这样Activity才会顺利的destory。

八、Application启动一个线程,为什么程序退出后还在运行
Android就是这么设计的,activity ,application这种退出,只是针对Main Thread,对于自己分发出来的其他thread,不会伴随着Main Thread的消亡而消亡,所以需要手动控制停止thread。
为了确保准确性,真正退出的时候都是杀进程的,那么所有子线程都没了,如若不然,不同的工具不同的线程各种跑,进程怎么都会存在的。相对来说Handler线程,问题不是很大。如果,从这个调度考虑,还是让系统自己去管理的好。
  相关解决方案