【Android】Handler和Handler Thread心得

本文详细介绍了Android中的Handler、HandlerThread、MessageQueue和Looper的工作原理。Handler用于发送和处理消息,Looper负责消息循环,MessageQueue存储消息,HandlerThread则提供了一个内置Looper的线程。文章强调了在子线程使用Handler前需要先创建Looper,同时讨论了如何在不阻塞UI线程的情况下使用HandlerThread处理任务,以及如何正确关闭消息循环。
摘要由CSDN通过智能技术生成

Handler

Android的消息机制主要指的是Hanlder的运行机制、Handler所附带的MessageQueue和Looper的工作过程,三者是一个整体的,只不过我们开发过程中接触比较多的是Hanlder而已。

Handler创建完成后,此时内部的Looper和MessageQueue就可以和Handler协同工作了,然后通过Handler的post发送一个Runable投递到Hanlder内部的Looper处理,也可以通过send发送一个message,这消息同样会在Looper处理,其实post方法最终也是通过调用send方法来完成的。
send方法被调动是会调用MessageQueue的enqueueMessage方法将这个消息放到消息队列中,然后Looper发现有新消息,就会处理这个消息。最终消息中的Runable、或者Handler的handlerMessage方法就会被调用。Looper是运行在创建Hanlder的线程中、或者执行线程的Looper,这样一来Handler中的业务逻辑就被切换到Handler所在的线程中执行。
Handler:相当于一个处理器,主要处理和绑定该handler线程中的message。每个handler都必须关联一个looper,并且二者是一一对应的。Handler负责消息的发送和处理:Handler发送消息给MessageQueue和接收Looper返回的消息并且处理消息。
MessageQueue:消息队列,顾名思义,内部存储一组消息,以队列的形式对外提供插入、删除工作。内部从存储结构不是真正的队列,而是采用单链表的数据结构存储消息,单链表在插入和删除上比较有优势。

  1. enqueueMessage():插入方法
  2. next():读取方法,伴随着删除。next是一个无限循环方法,如果消息队列中没有消息,就一直阻塞,有新消息到来是,next会返回这条消息并从单链表中移除。
  3. quit()、quitSafely():退出、安全退出方法。如果Looper.quit或者Looper.quitSafely被调用,就调用MessageQueue的quit、quitSafely通知消息队列退出,消息队列被标记为退出是,next就返回null==

Looper:中文翻译为循环,理解为消息循环。由于MessageQueue只是消息的存储单元,不去处理消息,而Looper就填补了这个功能。Looper会以无线循环的形式查看是否有新的消息,有的话就负责从内部的messageQueue中拿出一个message交给handler进行处理。这里handler是在UI线程中实现的,所以经过这么一个handler、 message机制,我们就可以回到UI线程中了。

  1. Looper(boolean quitAllowed):构造方法,是私有的
  2. Looper.prepare():为当前线程创建一个Looper,内部调用私有构造方法
  3. Looper.loop():开启消息循环,是一个死循环,只有MessageQueue.next返回null才推出。
  4. Looper.prepareMainLooper():给主线程ActivityThread创建Looper,由于主线程Looper方法比较特殊,所以提供一个单独方法
  5. Looper.getMainLooper():在任何地方获取主线程的Looper
  6. Looper.quit():直接退出Looper。
  7. Loop.quitSafely():只是设定一个退出标记,当把队列所以的消息处理完毕才安全退出。Looper退出后,Handler的send发送的消息会失败,测试send方法返回FALSE。
    Looper.quit()–&gtMessageQueue.quit,测试MessageQueue.next 返回null,Looper.loop退出死循环、也就是消息循环

ThreadLocal<T>:java中的一个特殊概念,传入泛型,并不是线程,作用是可以在每个线程中存储数据,作用域是当前线程,实现多个线程互不干扰的存取和修改数据。Hanlder创建的时候会采用当前线程的Looper来构造消息循环系统,那么Hanlder内部获取当前线程的Looper,就要使用到ThreadLocal了。ThreadLocal可以在不同线程中互不干扰的的存储并提供数据,通过ThreadLocal可以轻松的获取到每个线程的Looper。当然需要注意的是,线程是默认没有Looper的,如果需要使用Hanlder就必须为该线程创建Looper。我们经常用的主线程,也叫UI线程,其实是ActivityThread,在创建时候就被初始化Looper了,这也是主线程总默认可以使用Handler的原因

// Looper中的代码
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

[x] 调用Looper类的 prepare() 方法可以为当前线程创建一个消息循环,调用loop() 方法使之处理信息,直到循环结束。

[x] 我们要在子线程中调用Looper.prepare() 为一个线程开启一个消息循环,默认情况下Android中新诞生的线程是没有开启消息循环的。(主线程除外,主线程系统会自动为其创建Looper对象,开启消息循环。) Looper对象通过MessageQueue来存放消息和事件。一个线程只能有一个Looper,对应一个MessageQueue。 然后通过Looper.loop() 让Looper开始工作,从消息队列里取消息,处理消息。

[x] 注意:写在Looper.loop()之后的代码不会被执行,这个函数内部应该是一个循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。

[x] Handler有几个构造重载,如果构造时不提供Looper类对象参数,会获取当前线程的Looper对象,即将当前线程的消息循环作为Handler关联的消息循环。

[x] 其实Looper的作用就是把handler发送的消息放 到Queue中,并把消息广播给所有与这个Queue相关的handler,而Queue一般是主线程开启的时候就给这个线程分配了一个,所以你要与UI 主线程通信必须用于这个Queue相关联的handler对象才行,一般handler对象在那个线程中创建的就与那个线程的queue关联,所以在UI 线程中创建的handler对象就与UI线程通讯,这样我们就可以在子线程中发送消息给主线程,实现更新UI的功能。

//uiHandler在主线程中创建,所以自动绑定主线程,不需要放入onCreate中
    private 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值