Android基础知识(十):Handler的使用方式与注意事项
在使用Handler机制之前,需要向了解Handler机制的原理:Handler机制的实现与原理分析。
Handler使用方式因发送消息到消息队列的方式不同而不同,共有2中方式:Handler.sendMessage()和Handler.post()。
一、使用Handler.sendMessage()
- 线程切换(空消息)
一个简单的例子如下,在主线程中创建一个Handler,其handlerMessage()方法是运行在主线程的,当在子线程发送一个消息时,handlerMessage()会接收到消息,从而实现了线程的切换以及消息的处理。
上述的代码中,Handler发送的消息是一个空消息,如果只是单纯的发送一个空消息,那么可以使用Handler发送空消息的方法sendEmptyMessage(what)。 - 带数据的线程切换消息处理
Handler可以发送带有数据的Message,Message对象中有一个Object类型的obj属性,用于携带消息数据。使用Handler发送带有数据的消息,只需要将发送的数据赋值给obj,然后在处理消息的时候再把数据取出来即可,如下所示。
除了obj以外,Message还有两个int类型的属性:arg1、arg2可以用来发送一些简单的数据。其中之一就是what属性,what属性是int类型,用于标识消息。使用方式如下。
对于多个带有不同数据,并且所需的消息处理逻辑不一样的Message,可以使用Message的what属性来对不同的消息进行标识。
二、使用Handler.post()
Handler.post()的使用方式如下。
由Handler.post()的源码,可以得知Runnable会被封装成一个Message对象,然后通过sendMessge存放到MessageQueue中,封装的逻辑为:将Runnable赋值给Message的callback即可。
由Handler机制的实现与原理分析中对Handler源码的总结中,消息处理方式中,Message的callback的优先级最高,所以这个消息是由自己的callback也就是Runnable中的run方法进行处理的,而不再是Handler的handleMessage()方法。三、消息处理的线程
在前面的例子中,消息的处理都是在主线程,但是消息的处理事实上是运行在负责关系消息队列(MessageQueue)的Looper所在的线程的,而不一定是主线程。
如果创建一个Handler对象而没有给其指定它的Looper,那么它会默认使用当前线程的Looper。另外需要注意的是:主线程默认是有实现Looper.perpare()以及Looper.loop()方法的,也就是说如果指定Handler的Looper是主线程的Looper,那么不需要创建主线程的Looper以及开启Looper的消息轮询。
在子线程使用Handler,并且使得默认为消息处理在子线程的代码例子如下。
子线程使用Handler的几个注意事项:
- 在子线程使用Handler之前一定要先为子线程创建Looper
创建Looper的方式是直接调用Looper.prepare()方法。前面讲过创建Handler对象时如果没有给它指定Looper,那么它默认会使用当前线程的Looper,而线程默认是没有Looper的。 - 在同一个线程里,Looper.prepare()方法不能被调用两次
- 只有调用了Looper.loop()方法,Handler机制才能正常工作
- Looper.loop()方法一定在调用了Looper.prepare()方法之后调用
- 不要在主线程调用Looper.prepare()方法
Android系统创建主线程的时候就已经调用了Looper.prepare()方法和Looper.loop()方法。 - 当在子线程使用Handler时,如果Handler不在需要发送和处理消息,那么一定要退出子线程的消息轮询
Looper.loop()方法是死循环,如果不主动结束,那么其会一直运行,导致子线程一直运行而不结束。
四、为Handler指定Looper以及Handler的其他使用方法
- 为Handler指定Looper
指定Handler的Looper方法如下。 - Handler的其他使用方法
Handler除了提供post()和sendMessage()方法以外,还提供了一系列的发送消息的方法。比如延时发送消息和定时发送消息:
五、小知识点
- 使用Message.obtain()来获取Message
在使用中,创建一个Message对象,并不推荐通过硬初始化(new)的方式,而是使用Message.obtain()方法。
Android会为Message提供一个缓存池,把使用过的消息缓存起来,方便下次使用。使用Message.obtain()方法获取一个消息时,会先从缓存池获取,如果缓存池没有消息,才会去创建消息,从而优化内存。 - 同一个Message不要发送两次
由于Message都是存放到MessageQuue中存放的,如果一个Message对象已经在MessageQueue中,再次把它存放到MessageQueue时会报错。 - Android提供的实现Handler的类和方法
Android中提供的实现Handler的类和方法:runOnUiThread()方法、View的post()方法、HandlerThread类等。
参考资料:Android Handler的使用方式和注意事项