在android中经常会有延时执行的需求。这里对比一下几种延时执行实现方式的优劣。
1、Handler
通过Handler的postDelayed来实现延时
Integer time = 2000;
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
Intent intent = new Intent(LaunchActivity.this,MainActivity.class);
startActivity(intent);
LaunchActivity.this.finish();
}
},time);
Handler的源码位于**/frameworks/base/core/java/android/os/Handler.java**,postDelayed通过调用sendMessageDelayed、sendMessageAtTime、enqueueMessage,来到MessageQueue类的enqueueMessage方法:
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
/*postDelayed最后就是把Message的when设置为延迟的时间,然后插入MessageQueue,交给looper去执行;此时的阻塞是会释放cpu资源的,下面的代码主要用于唤醒。
*/
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
所以,通过Handler来设置延迟并不会占用CPU的资源。
2、TimerTask
创建一个TimerTask,交给Timer的schedule执行:
TimerTask task = new TimerTask() {
@Override
public void run() {
Intent intent = new Intent(LaunchActivity.this,MainActivity.class);
startActivity(intent);
LaunchActivity.this.finish();
}
};
Timer timer = new Timer();
timer.schedule(task, 2000);
这种实现基于Timer类,而Timer的实现则是通过内部开启一个TimerThread,TimerThread在run方法中调用mainLoop:
/**
* The main timer loop. (See class comment.)
*/
private void mainLoop() {
while (true) {
try {
TimerTask task;
boolean taskFired;
synchronized(queue) {
// Wait for queue to become non-empty
while (queue.isEmpty() && newTasksMayBeScheduled)
queue.wait();
/*这里可以看到,就是通过wait等待,然后notify唤醒来实现延迟*/
if (queue.isEmpty())
break; // Queue is empty and will forever remain; die
// Queue nonempty; look at first evt and do the right thing
long currentTime, executionTime;
task = queue.getMin();
synchronized(task.lock) {
if (task.state == TimerTask.CANCELLED) {
queue.removeMin();
continue; // No action required, poll queue again
}
currentTime = System.currentTimeMillis();
executionTime = task.nextExecutionTime;
if (taskFired = (executionTime<=currentTime)) {
if (task.period == 0) { // Non-repeating, remove
queue.removeMin();
task.state = TimerTask.EXECUTED;
} else { // Repeating task, reschedule
queue.rescheduleMin(
task.period<0 ? currentTime - task.period
: executionTime + task.period);
}
}
}
if (!taskFired) // Task hasn't yet fired; wait
queue.wait(executionTime - currentTime);
}
if (taskFired) // Task fired; run it, holding no locks
task.run();
} catch(InterruptedException e) {
}
}
}
TimerTask实现延迟的方式会新起一根线程,通过线程的wait和notify来实现延迟。
3、Thread
可以通过设置Thread的sleep来实现延迟:
new Thread() {
@Override
public void run() {
super.run();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Intent intent = new Intent(LaunchActivity.this,MainActivity.class);
startActivity(intent);
LaunchActivity.this.finish();
}
}.start();
这种方式也会新起一根线程。
总结
三种方式,显然Handler的开销更小,TimerTask和Thread.sleep都需要新起线程。