我们都知道在Android中,一般的需求是子线程执行耗时任务,UI线程负责更新界面,所以我们一般都是子线程向主线程发送消息。关于子线程向主线程发送消息时要用到Handler机制,很多时候面试会让描述Android的Handler机制,那么Handler的机制是什么?下面就来解释下。
当子线程要向主线程发送一条消息时,如果发消息需要传递一些数据的话,首先要在子线程构建一个Message对象,然后将要发送的消息的数据放在其中,然后在主线程构建Handler对象,使用Handler对象的sendMessage(Message msg)
方法将消息发出,之后消息会进入主线程的MessageQueen队列中等待处理,主线程的Looper会执行Looper.loop()
方法会一直轮循MessageQueen队列,从队列中取出待处理的message,交由Handler的handleMessage()
方法处理。如果发消息不需要传递数据则可以直接使用sendEmptyMessage(int what)
方法。
这么做是没问题的,虽然我们的机制里用到了Looper,但貌似我们一直没见过它,这是因为UI线程会默认执行Looper.pepare()
,Looper.loop()
方法,所以不需要我们手动去调用。
但是如果是主线程向子线程发送消息呢?如果在创建Handler时不指定与其绑定的Looper对象,系统默认会将当前线程的Looper绑定到该Handler上。所以,Handler要在子线程创建对象,然后必须要手动调用Looper.pepare()
,Looper.loop()
这两个方法。
下面还是通过代码来说明一下问题吧。
第一种方式,创建Handler对象时不绑定Looper
子线程向主线程发送消息:
比如下面的这个例子就是从子线程向主线程发送消息告知进度,然后主线程收到消息后更新ProgressBar的进度。
|
|
效果图:
可以看出,基本上的操作就跟我们描述的一样。
主线程向子线程发消息
这种情况就稍微有点复杂了,需要手动操作Looper,而且Handler对象也得在子线程创建(需要在哪个线程处理消息则Handler就需要在哪个线程创建)。
|
|
这样实现每点击一次按钮便向子线程发送一条消息,子线程接收到消息后使用Toast显示。
第二种方式,创建Handler对象时绑定Looper
在主线程中,可以创建Handler对象后,其将自动与主线程的Looper对象绑定,所以可以直接使用;在非主线程中直接这样创建Handler则会报错,因为Android系统默认情况下非主线程中没有开启Looper,而Handler对象必须绑定Looper对象。这种情况下,需先在该线程中手动开启Looper(Looper.prepare()–>Looper.loop()),然后将其绑定到Handler对象上;或者通过Looper.getMainLooper(),获得主线程的Looper,将其绑定到此Handler对象上。
下面来看一种子线程给子线程发消息的案例:
|
|
通过在Handler的构造方法中传入Looper.getMainLooper()
参数将Handler在主线程创建了,所以不用调用Looper.prepare()
跟Looper.loop()
方法。通过运行效果我们还是能看出handler是运行在主线程的:
现在来看看不与主线程Looper绑定的方式,这个时候就需要在创建handler的时候手动调用Looper.prepare()
跟Looper.loop()
方法了:
|
|
效果图:
可以看得出来,这次handler的线程id就不是1了,也就是说不在主线程了。
关于在子线程更新UI的方法
如果需要在子线程更新UI,有两种方法:
- 如果是在Activity中,则可以直接在子线程中使用
runOnUiThread(Runnable action)
方法进行更新UI。 - 使用
Handler mHandler = new Handler(Looper.getMainLooper())
将Handler对象与UI线程绑定,然后在子线程中使用Handler的post(Runnable r)
方法,重写Runnable的run()
方法,在run()
方法中更新UI。
关于这两个方法的区别,从runOnUiThread(Runnable action)
方法源码中可以看出来:
|
|
可以看出runOnUiThread(Runnable action)
方法内部也是进行了判断,如果调用该方法的线程不是UI线程,则调用了Handler的post(Runnable r)
方法来更新UI;如果是在UI线程调用的,则直接进行更新UI操作。二者不同的地方是runOnUiThread(Runnable action)
这个方法只有Activity有。