欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android定时器实现的几种方式整理及removeCallbacks失效问题解决

程序员文章站 2023-12-03 14:41:40
实现定时器有很多种方式,在这里我简单的介绍几种方式 (1)使用handler + runnable的方式 复制代码 代码如下: handler handler = new...
实现定时器有很多种方式,在这里我简单的介绍几种方式
(1)使用handler + runnable的方式
复制代码 代码如下:

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
Android定时器实现的几种方式整理及removeCallbacks失效问题解决
图:两个按钮,一个将runnable加到消息队列中,一个将runnable从消息队列中移除。该runnable每1秒钟打印一次日志。
复制代码 代码如下:

<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的方式
复制代码 代码如下:

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
复制代码 代码如下:

handler handler = new handler() {
public void handlemessage(message msg) {
super.handlemessage(msg);
system.out.println("update...");
}
}

2.新建一个实现runnable接口的线程类,用一个boolean 来控制线程开始和结束 boolean islive = true如下:
复制代码 代码如下:

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.在需要启动线程的地方加入下面语句
复制代码 代码如下:

new thread(new mythread()).start();

4.取消的话将islive设置为false就行了
今天主要介绍这三种方法,写的不好的地方希望大家指出,谢谢!