Android面试相关Android技术知识Android知识

Android 开发之Handler的前世今生

2017-04-25  本文已影响244人  Angels_安杰

文章独家授权公众号:码个蛋
更多分享:http://www.cherylgood.cn

目前:假设我们需要在子线程中更新UI,一般有以下几种方式:


  • 1、ThreadLocal:每个使用该变量的线程提供独立的变量副本,每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。ThreadLocal内部是通过map进行实现的;
  • 2、Looper:可以理解为循环器,就是扶着管理一个消息循环队列(MessageQueue)的;
  • 3、MessageQueue:消息队列,用来存放handler发布的消息
  • 4、Message:消息体,封装了我们传输消息所需的数据结构。
小结: Handler会存有Looper对象以及消息队列mQueue,通过关联looper与mQueue,可以想象,handler要把message插入消息队列中,最直接的方式当然是拿到消息队列的实例,实现消息的发送;

小结:Looper里面会存储当前的线程,以及所管理的消息队列mQueue,一个Looper只会管理一个消息队列MessageQueue;

  • 1、 调用 Looper.prepare(); 初始化所需的looper以及messageQueue
  • 2、 实例化一个handler对象,我们可以在handleMessage获得message做一些操作,此时handleMessage方法是在当前的Looper中执行的,也就是说,如果当前的looper是UI Looper,那么你可以更新UI,如果当前looper不是UI Looper,那么你更新UI肯定会报错,你可能会说,我用handler时,好像都不用调用Looper.prepare();,我怎么知道我当前的looper是UI的还是不是呢,其实系统一般默认都帮我们获取了UI 的Looper,后面我们会讲解到;
  • 3、调用 Looper.loop();让Looper跑起来吧!

小结:

looper主要做了如下工作:

  • 1、将自己与当前线程关联在一起,通过ThreadLocal存储当前线程的looper,确保当前线程只有一个looper实例;
  • 2、创建一个MessageQueue与当前looper绑定,通过prepare方法控制looper只能有一个messageQueue实例;
  • 3、调用loop()方法,不断从MessageQueue中去取消息,通过调用msg.target.dispatchMessage(msg)处理;



总结:
  • 1、在Looper.prepare()中会通过sThreadLocal保存一个looper实例,控制当前线程只能有一个looper实例;
  • 2、创建looper实例时,会创建一个MessageQueue与looper关联;
  • 3、因为looper只会存在一个实例,所以 当前线程也会只存在一个MessageQueue队列;
  • 4、调用Looper.loop()让looper跑起来吧,然后looper就可以不停的从MessageQueue把消息拿出来,然后通过调用msg.target.dispatchMessage(msg)处理消息,也是让消息最终进入我们的Handler.handleMessage方法,被我们给处理了;所以我们在实例化handler时需要重写handleMessage方法;
  • 5、实例化Handler时,handler中会获得当前线程的looper以及looper的messageQueue;
  • 6、在调用sendMessage发送消息时,最终会调用enqueueMessage方法,在enqueueMessage方法里会将msg.target=handler,讲handler关联到msg中,这样looper在取出messageQueue中的消息时,才知道该消息是要发给那个handler处理的,将handler与msg关联后,就将msg加入队列中去了,等待looper处理。

  • 1、创建massage对象时,推荐使用obtain()方法获取,因为Message内部会维护一个Message池用于Message的复用,这样就可以避免 重新new message而冲内心分配内存,减少new 对象产生的资源的消耗。
  • 2、handler 的handleMessage方法内部如果有调用外部activity或者fragment的对象,一定要用弱饮用,handler最好定义成static的,这样可以避免内存泄漏;为什么呢?因为一但handler发送了消息。而handler内部有对外部变量的引用,此时handler已经进入了looper的messageQueue里面。此时activity或者fragment退出了可视区域,但是handler内部持有其引用且为强引用时,其就不会立即销毁,产生延迟销毁的情况。

更多分享:http://www.cherylgood.cn

上一篇 下一篇

猜你喜欢

热点阅读