Handler vs Timer

在我们Android开发过程中,经常需要执行一些短周期的定时任务,这时候有两个选择Timer或者Handler。然而个人认为:Handler在多个方面比Timer更为优秀,更推荐使用。

一.易用性

1. 可重复执行

  • Handler可以重复执行某个任务。
  • Timer若在某个任务执行/取消之后,再次执行则会抛出一个IllegalStateException异常。为了避免这个异常,需要重新创建一个Timer对象。

2. 周期可调整

若想要执行一个越来越快的定时任务,Handler可以做到,而Timer则消耗较大。

  • Handler
private Handler handler = new Handler();

int mDelayTime = 1000;
private Runnable runnable = new Runnable() {
public void run() {
update();
if (mDelayTime > 0) {
handler.postDelayed(this,mDelayTime);
mDelayTime -= 100;
}
}
};
handler.postDelayed(runnable,1000);

如以上例子,就可以实现对周期的动态调整。

  • Timer的scheduleAtFixedRate(TimerTask task, long delay, long period)只能执行固定周期的任务,所以不可以动态地调整周期。若想要动态调整,则需要在执行玩一个定时器任务后,再启动一个新的任务时设置新的时间。

3. UI界面更新

  • Handler:在创建的时候可以指定所在的线程,一般在Activity中构建的,即主线程上,所以可以在回调方法中很方便的更新界面。
  • Timer:异步回调,所以必须借助Handler去更新界面,不方便。

    既然都得用Handler去更新界面了,为何不如把定时的功能也交给Handler去做呢?

二.内存占比

Timer比Handler更占内存。

接下来的Demo例子通过两种方法循环地打印日志,然后通过MAT插件来查看这两个类所需要调用的对象所产生的占比。

int mCount = 0;
private void startTimer() {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
Log.i("JKL", "" + mCount);
mCount++;
}
}, 0, 200);
} private void startHandler() {
final Handler mHandler = new Handler();
mHandler.post(new Runnable() {
@Override
public void run() {
Log.i("JKL", "" + mCount);
mCount++;
mHandler.postDelayed(this, 200);
}
});
}

可以通过创建一个新的Android工程,在onCreate方法中调用以上startTimer或startHandler任意一个方法来测试。

以下是MAT的测试结果。

Timer相关对象的内存占比

共有5个对象,占用1192B。

Handler相关对象的内存占比

我们可以看到上面有2个Handler,这时候你是否会疑惑呢?其实一个是我们生成的Handler,另外一个是Activity默认生成的,存在于ViewRootImp中,这涉及到ViewTree的知识,此处不便展开。

不过我们可以知道,我们自己构建的Handler,最多也就只占64B。

在使用Handler的时候,还需要用到Runnable,不过也只占了16B。

所以,使用Handler的方式来作为定时器,最多也就是80B。


以上可以得出结论,相比起Timer方式的定时器占用1192B,Handler的方式占用资源会小很多,只有1/60。

所以Handler的方式比较节省内存。

写到这里,想到一个点,Timer是创建一个线程去计数的,而Handler是在默认主线程运行的。假若Handler也用一个异步线程去运行,会不会耗很多资源呢?

以下是测试代码:

private void startHandler() {
HandlerThread thread = new HandlerThread("Test");
thread.start();
final Handler mHandler = new Handler(thread.getLooper());
mHandler.post(new Runnable() {
@Override
public void run() {
Log.i("JKL", "" + mCount);
mCount++;
mHandler.postDelayed(this, 200);
}
});
}

以上用一个HandlerThread来启动一个新的线程。再看看内存占比:

可以看到HandlerThread也只是占了96B的内存。


综上所述,Handler内存占比低!而且低了不少。

无论从易用性还是内存占比出发,Handler更胜一筹.

Handler vs Timer,究竟该用哪个?的更多相关文章

  1. android Handler vs Timer

    Handler vs Timer 在我们Android开发过程中,经常需要执行一些短周期的定时任务,这时候有两个选择Timer或者Handler.然而个人认为: Handler 在多个方面比Timer ...

  2. handler和Timer的用法

    final Handler handler = new Handler(){public void handleMessage(Message msg){if (msg.what == 0x123){ ...

  3. 使用Handler和Timer+Timertask实现简单的图片轮播

    布局文件就只放了一个简单的ImageView,就不展示了. 下面是Activity package com.example.administrator.handlerthreadmessagedemo ...

  4. Timer.4 - Using a member function as a handler

    In this tutorial we will see how to use a class member function as a callback handler. The program s ...

  5. android 定时器(Handler Timer Thread AlarmManager CountDownTimer)

    Android实现定时任务一般会使用以上(Handler Timer Thread AlarmManager CountDownTimer)五种方式.当然还有很多组合使用(比如Handler+Thre ...

  6. 倒计时 总结 Timer Handler CountDownTimer RxJava MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  7. 倒计时实现方案总结 Timer Handler

    利用Timer实现倒计时 @BindView(R.id.send) Button send;//发送验证码 private int time = 60;//倒计时 private Timer time ...

  8. Android学习之Handler消息传递机制

    Android只允许UI线程修改Activity里的UI组件.当Android程序第一次启动时,Android会同时启动一条主线程(Main Thread),主线程主要负责处理与UI相关的事件,如用户 ...

  9. 从源码角度深入理解Handler

    为了获得良好的用户体验,Android不允许开发者在UI线程中调用耗时操作,否则会报ANR异常,很多时候,比如我们要去网络请求数据,或者遍历本地文件夹都需要我们在新线程中来完成,新线程中不能更新UI, ...

随机推荐

  1. 如何使用 awk 输出文本中的字段和列

    首先我们要知道,awk 能够自动将输入的行,分隔为若干字段.每一个字段就是一组字符,它们和其他的字段由一个内部字段分隔符分隔开来. 如果你熟悉 Unix/Linux 或者懂得 bash shell 编 ...

  2. Maven Dependencies 不见了

    解决办法: 1. 选中项目 --> 右键 --> Maven --> Disable Maven Nature 此时,右键菜单中将隐藏[Maven]菜单选项 2. 选中项目 --&g ...

  3. P2P终结者和反P2P终结者如何使用

    1 安装软件并运行,首先扫描网络,第一台控制机就是自己,你可以查看IP,和命令提示符下的IP吻合. 2 点击高级选项,指定本机网络环境和网卡 3 控制规则设置,首先设置全局限速模板,其他的差不多. 4 ...

  4. 关于Fragment的懒加载问题

    为了达到界面效果,我们有时需要使用到TabLayout+ViewPager的方式来布局界面,然而ViewPager的adapter总是默认把与当前可见的fragment相邻的两个fragment给加载 ...

  5. 在LoadRunner中进行Base64的编码和解码

    <Base64 Encode/Decode for LoadRunner>这篇文章介绍了如何在LoadRunner中对字符串进行Base64的编码和解码: http://ptfrontli ...

  6. iOS_Xcode怎样准确定位到产生异常的出错代码

    当应用程序出现异常而导致崩溃时, 可能光标仅仅提示异常出如今主函数代码处,例如以下图所看到的: 这样的情况下.即使看了日志. 也可能仍不清楚详细是哪一句代码产生了异常. 因此,须要手动设置异常断点. ...

  7. iTunes 无法添加 iPhone 自定义铃声

    本篇文章由:http://xinpure.com/itunes-unable-to-add-iphone-custom-ringtones/ 新版本 iTunes 需要在 菜单栏 -> 文件 中 ...

  8. 在go中使用leveldb --levi

    github上有个比较好用的leveldb go wrapperlevigo, 安装之前需现在机器上安装leveldb 当前版本的LevelDB没有带安装脚本,需自行编译安装,过程如下: instal ...

  9. LaTeX 在编译时出现 File ended while scanning use of \@writefile错误

    LaTeX -在修改论文过程中,重新编译时.出现了File ended while scanning use of \@writefile错误,如以下所示: 问题出现的原因: 因为aux文件没有完整输 ...

  10. 使用C#开发ActiveX控件[Obsolete]

    文章出处:http://www.cnblogs.com/yilin/archive/2009/09/15/1567332.html 附件下载(源代码+安装文件+教程) 0. 前言 ActiveX控件以 ...