zoukankan      html  css  js  c++  java
  • Android 定时器实现的几种方式和removeCallbacks失效问题详解

    实现定时器有很多种方式,在这里我简单的介绍几种方式
    
    (1)使用Handler + Runnable的方式
    
    [java] view plain copy
    在CODE上查看代码片派生到我的代码片
    
        Handler handler = new Handler();  
        Runnable runnable = new Runnable() {  
              
            @Override  
            public void run() {  
                //你要做的事  
                //......  
                System.out.println(Thread.currentThread().getName());  
                handler.postDelayed(runnable, 1000);  
            }  
        };  
    
    然后调用handler.post(runnable);就能启动定时器,这里是每隔1s打印线程名字,从打印中我们可以知道,他并没有另开线程,而是运行在UI线程当中,当你要取消定时器的时候,只需要调用handler.removeCallbacks(runnable)就可以了。
    
    上面中有一个问题,有时候你会发现removeCallbacks有时候会失效,不能从消息队列中移除,看下面的demo

    图:两个按钮,一个将Runnable加到消息队列中,一个将Runnable从消息队列中移除。该Runnable每1秒钟打印一次日志。
    
    [java] view plain copy
    在CODE上查看代码片派生到我的代码片
    
        <span style="font-family:Courier New;">package com.example.demoactivity;  
          
        import android.app.Activity;  
        import android.os.Bundle;  
        import android.os.Handler;  
        import android.view.View;  
        import android.view.View.OnClickListener;  
        import android.widget.Button;  
          
        public class TimerActivity extends Activity{  
            Handler handler = new Handler();  
            Runnable runnable = new Runnable() {  
                  
                @Override  
                public void run() {  
                    System.out.println("update...");  
                    handler.postDelayed(runnable, 1000);  
                }  
            };  
          
            @Override  
            protected void onCreate(Bundle savedInstanceState) {  
                super.onCreate(savedInstanceState);  
                setContentView(R.layout.timer);  
                  
                Button mButtonStart = (Button) findViewById(R.id.button1);  
                Button mButtonStop = (Button) findViewById(R.id.button2);  
                  
                mButtonStart.setOnClickListener(new OnClickListener() {  
                      
                    @Override  
                    public void onClick(View v) {  
                        handler.post(runnable);  
                    }  
                });  
                  
                mButtonStop.setOnClickListener(new OnClickListener() {  
                      
                    @Override  
                    public void onClick(View v) {  
                        handler.removeCallbacks(runnable);  
                    }  
                });  
            }  
              
        }</span><span style="font-family: Georgia, 'Times new roman', Times, san-serif;">  
        </span>  
    
    结果:
    (1)start –>  输出 –> stop–> 停止输出
    (2)start –> 输出 –>  Background –> Front –> stop->继续输出
    
    当Activity进入后台运行后再转入前台运行,removeCallbacks无法将updateThread从message queue中移除。
    这是为什么呢?
    在Activity由前台转后台过程中,线程是一直在运行的,但是当Activity转入前台时会重新定义Runnable runnable;也就是说此时从message queue移除的runnable与原先加入message queue中的runnable并非是同一个对象。如果把runnable定义为静态的则removeCallbacks不会失效,对于静态变量在内存中只有一个拷贝(节省内存),JVM只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配,我们做如下修改就能解决上面的这个问题
        static Handler handler = new Handler();  
        static Runnable runnable = new Runnable() {  
              
            @Override  
            public void run() {  
                System.out.println("update...");  
                handler.postDelayed(runnable, 1000);  
            }  
        };  
    
    (2)使用Timer的方式
    
    [java] view plain copy
    在CODE上查看代码片派生到我的代码片
    
        Timer timer = new Timer();  
        timer.schedule(new TimerTask() {  
                              
            @Override  
            public void run() {  
                System.out.println("update....");  
            }  
        }, 0, 1000);  
    
    上面的每一秒打印语句,run方法是运行在子线程,不能直接在里面更新UI操作,这里需要注意下,取消的话调用timer.cancel()就能移除任务了
    
    (3)采用Handle与线程的sleep(long )方法
    
    1.定义一个Handler类,用于处理接受到的Message
    
    [java] view plain copy
    在CODE上查看代码片派生到我的代码片
    
        Handler handler = new Handler() {  
                public void handleMessage(Message msg) {  
                    super.handleMessage(msg);  
                    System.out.println("update...");  
                }  
            }  
    
    2.新建一个实现Runnable接口的线程类,用一个boolean 来控制线程开始和结束  boolean isLive = true如下:
    
    [java] view plain copy
    在CODE上查看代码片派生到我的代码片
    
        public class MyThread implements Runnable {  
                @Override  
                public void run() {  
                    while (isLive) {  
                        try {  
                            Thread.sleep(1000);// 线程暂停1秒,单位毫秒  
                            Message message = new Message();  
                            message.what = 1;  
                            handler.sendMessage(message);// 发送消息  
                        } catch (InterruptedException e) {  
                            e.printStackTrace();  
                        }  
                    }  
                }  
            }  
    
    3.在需要启动线程的地方加入下面语句
    
    [java] view plain copy
    在CODE上查看代码片派生到我的代码片
    
        new Thread(new MyThread()).start();  
    
    4.取消的话将isLive设置为false就行了
    
    今天主要介绍这三种方法,写的不好的地方希望大家指出,谢谢!
  • 相关阅读:
    New version of VS2005 extensions for SharePoint 3.0
    QuickPart : 用户控件包装器 for SharePoint Server 2007
    随想
    发布 SharePoint Server 2007 Starter Page
    如何在SharePoint Server中整合其他应用系统?
    Office SharePoint Server 2007 中文180天评估版到货!
    RMS 1.0 SP2
    SharePoint Server 2007 Web内容管理中的几个关键概念
    如何为已存在的SharePoint站点启用SSL
    Some update information about Office 2007
  • 原文地址:https://www.cnblogs.com/yaowen/p/5667530.html
Copyright © 2011-2022 走看看