handler

简介: handler

1、Handler 实现机制


Handler 机制有几个核心类:Handler、Looper、Message、MessageQueue。


Handler 机制是一个典型的生产者消费者模式——多个生产者,一个消费者,该模式是处理线程安全的一个经典模式


Message


Message 是 Handler 接收和处理的消息对象,内部使用链表实现一个消息池,用于重复利用,

避免大量创建消息对象,造成内存浪费。用于在不同线程之间交换数据。


Handler


主要用来发送和处理消息。发送消息一般是使用 Handler 的 sendMessage()方法,消息经过处理后,最终传递到 Handler 的 handlerMessage()方法中。


MessageQueue


消息队列,它主要用来存放所有通过 Handler 发送的消息,这部分消息会一直存在于消息队列中,等待被处理。注意:每个线程中只会有一个 MessageQueue 对象。


Looper


每个线程中 MessageQueue 的管理者,调用 Looper 的 loop()方法后,就会进入到一个无限循环当中,每当发现 MessageQueue 中存在一条消息,就会将其取出传递到 Handler 的 handleMessage()方法当中。


2、Handler 创建流程

Looper.prepare

public static void prepare() {
        prepare(true);
    }
 
    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }
private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }


创建了 Looper 对象,在构造函数中创建了 MessageQueue


然后将 Looper 对象通过 ThreadLocal 跟当前的主线程绑定


new Handler()


通过 Looper 类中的 ThreadLocal 从主线程中获取到 Looper 对象


然后通过 Looper 对象获取到 MessageQueue 的应用


handler.sendMsg()


找到 MessageQueue 对象


然后 msg.target=this,将 handler 对象成为 msg 的一个成员变量

最后把 msg 添加到 MessageQueue 中

Looper.loop()

找到 MessageQueue

然后开启死循环遍历 MessageQueue 消息池


当获取到 msg 的时候,通过 msg.target 找到发送这个 msg 的 handler


然后调用 handler 的 dispatchMessage()方法


3、一个线程有几个 Handler?


一个线程可以用有多 Handler,因为 Handler 最终是被 Message 持用的(post 里面的 Runnable 最终也会被包装成一个 Message),以便 Looper 在拿到 Message 后调用 Handler 的 dispatchMessage 完成回调,而且项目中仔细去看也确实如此,我们可以每个 Activity 中都创建一个 Handler 来处理回调到主线程的任务。


4、一个线程有几个 Looper?


一个线程只能拥有一个 Looper,这里从源码中就可以看到,sThreadLocal.set 只调用了一次,如果再次调用 prepare 会判断 sThreadLocal.get 是否为空,如果不为空就直接抛出异常了,也就是同一线程多次调用 prepare 方法会直接崩溃,这里也是避免了程序去修改某个线程已经设置好的 Looper 值。


5、为何主线程可以使用 Handler?如果想要在子线程中使用 Handler 机制要做些什么准备?


Handler 的构造中(无论调用哪个最终都会走到这里),是需要判断当前线程是否存在 Looper 的,如果不存在会直接抛出异常,主线程之所以可以使用 Handler 是因为系统帮在 ActivityThread 中已经帮我们创建了 Looper 并且已经让它运行了起来。

如果我们现在子线程中使用 Handler 的话,,其实就是两步,在子线程中调用 Looper.prepare() 和 Looper.loop() 即可,prepare 帮我们在对应线程创建 Looper,loop 让刚刚创建好的 Looper 运行起来。

6、我们使用 Message 时应该如何创建它?


创建的它的方式有两种,一种是直接 new 一个 Message 对象,另一种是通过调用 Message.obtain() 的方式去复用一个已经被回收的 Message,当然日常使用者是推荐使用后者来拿到一个 Message,因为不断的去创建新对象的话,可能会导致垃圾回收区域中新生代被占满,从而触发 GC。


通过 Message 的静态方法 Message.obtain();


通过 Handler 的公有方法 handler.obtainMessage()。


7、可以存在多个 Handler 往 MessageQueue 中添加数据(发消息时各个 Handler 可能处于不同线程),那它内部是如何确保线程安全的?


存储消息


在往消息队列里面存储消息时,会拿当前的 MessageQueue 对象作为锁对象,这样通过加锁就可以确保操作的原子性和可见性了。


读取消息


读取消息也是同理,也会拿当前的 MessageQueue 对象作为锁对象,来保证多线程读写的一个安全性。


8、handler postDelay 这个延迟是怎么实现的?


handler.postDelay并不是先等待一定的时间再放入到MessageQueue中,而是直接进入MessageQueue,以MessageQueue的时间顺序排列和唤醒的方式结合实现的。


Handler.postDelayed()精确延迟指定时间的原理_沙漠一只雕得儿得儿的博客-CSDN博客


9、looper 的无限循环为什么不会ANR


安卓是由事件驱动的,Looper.loop不断的接收处理事件,每一个点击触摸或者Activity每一个生命周期都是在Looper.loop的控制之下的,looper.loop一旦结束,应用程序的生命周期也就结束了。


思考一下发送ANR情况:事件没有得到处理;事件正在处理,但是没有及时完成。 对事件进行处理的就是looper,所以只能说事件的处理如果阻塞会导致ANR,looper的无限循环不会导致ANR。


而且主线程Looper从消息队列读取消息,当读完所有消息时,主线程阻塞。子线程往消息队列发送消息,并且往管道文件写数据,主线程即被唤醒,从管道文件读取数据,主线程被唤醒只是为了读取消息,当消息读取完毕,再次睡眠。因此loop的循环并不会对CPU性能有过多的消耗。


10、Handler 引起的内存泄露原因以及最佳解决方案?


原因:Handler 允许我们发送延时消息,如果在延时期间用户关闭了 Activity,那么该 Activity 会泄露。这个泄露是因为 Message 会持有 Handler,而又因为 Java 的特性,内部类会持有外部类,使得 Activity 会被 Handler 持有,这样最终就 导致 Activity 泄露。


解决:将 Handler 定义成静态的内部类,在内部持有 Activity 的弱引用,并在 Acitivity 的 onDestroy()中调用 handler.removeCallbacksAndMessages(null)及时移除所有消息。

目录
相关文章
|
4天前
|
消息中间件 存储
Handler
Handler
20 1
|
缓存 Java Shell
Handler 的 Message 实例怎么获得?为什么不是直接 new?
Handler 的 Message 实例怎么获得?为什么不是直接 new?
|
消息中间件 存储 项目管理
handler+message【消息机制】
handler+message【消息机制】
139 0
handler+message【消息机制】
|
JSON 数据格式
09准备将Handler的返回值写入ServletResponse
在RequestMappingHandlerAdapter初始化完成后设置默认的HandlerMethodReturnValueHandler HandlerMethodReturnValueHandler体系介绍 HandlerMethodReturnValueHandler的执行流程
183 0
|
消息中间件 存储 Java
你真的了解Handler吗
今天发一个以前的文章,关于Handler的全面解析,大家看看吧~「周末愉快」!
168 0
你真的了解Handler吗
|
Unix 调度 索引
I/O Handler的管理(3)
I/O Handler的管理(3)
95 0
|
消息中间件 Android开发
【Android 异步操作】手写 Handler ( Handler 发送与处理消息 | Handler 初始化 | 完整 Handler 代码 )
【Android 异步操作】手写 Handler ( Handler 发送与处理消息 | Handler 初始化 | 完整 Handler 代码 )
124 0
|
消息中间件 Android开发 程序员
浅谈Handler
前言 积土成山,风雨兴焉;积水成渊,蛟龙生焉;积善成德,而神明自得; Handler消息传递机制 出于性能优化考虑,Android的UI操作并不是线程安全的,这意义着如果有多个线程并发操作UI组件,则可能导致线程安全问题。
1374 0
|
消息中间件 Android开发 调度