handler简单研究
handler原理构成了线程模型中简单的生产者-消费者模型:生产者和消费者在同一时间段内共用同一个存储空间,生产者往存储空间中添加数据,消费者从存储空间中取走数据。不管是生产者(子线程)还是消费者(主线程)都只依赖缓冲区(handler),生产者消费者之间不会相互持有,使他们之间没有任何耦合
1.简单使用
handler主要看looper,handler,messagequeue
首先在activitythread里面执行Looper.prepareMainLooper()新建looper
最后一句话得知通过threadlocal绑定looper来保证一个线程只有一个looper,再看new looper
新建一个messagequeue来保证一个线程只有一个messagequeue,最后调用looper.loop方法
上图是阉割过的源码,queue.next()方法是从头部开始取的,看使用
handler简单使用主线程新建handler通过回调handlermessage来接受子线程发送的消息,子线程通过handler的sendmessage方法来发送消息。
send message
点击源码可以看都是在handler.java文件下面的
最终都会走到enqueuemessage上
msg.target = this
该代码让msg绑定当前handler,因为匿名内部类都是默认持有外部类的引用的,handler又隐形持有activity对象,所以如果外部的activity要销毁,handler可能有消息还没处理,垃圾回收机制就无法回收activity造成内存泄漏(解决办法弱引用)
queue.enqueuemessage
调用messagequeue里面的方法
msg是个单链表优先级队列,以时间为顺序
总结
1.handler使用sendmessage把message通过enqueuemessage丢到messagequeue里面再由loop对象调用looper方法,通过messagequeue里面的.next方法取出来再调用handler的dispatchmessage方法丢出去。
从某地偷的图问题
1.handler是怎么保证线程安全的
这里使用synchronized锁是一个内置锁,来保证message进入messagequeue和出去next()不会混乱,因为一个线程只有一个messagequeue,主线程一次都只会处理一个消息,其他的都需要等待,那么这个时候消息队列就不会出现混乱。
2. 一个线程有几个 Handler?
这不是你随便你想创建几个就有几个
3.一个线程有几个 Looper?如何保证?
一个线程只有一个looper,因为新建looper时候调用prepare时候里面有个threadlocal方法来保证一个线程只有一个looper
4.Handler内存泄漏原因? 为什么其他的内部类没有说过有这个问题?
msg绑定当前handler,因为匿名内部类都是默认持有外部类的引用的,handler又隐形持有activity对象,所以如果外部的activity要销毁,handler可能有消息还没处理,垃圾回收机制就无法回收activity造成内存泄漏(解决办法弱引用)
5.为何主线程可以new Handler?如果想要在子线程中new Handler 要做些什么准备?
主线程的activitythread里面已经帮你创建好了,子线程创建handler需要新建looper.prepare,looper.loop,looper.quit
6.子线程中维护的Looper,消息队列无消息的时候的处理方案是什么?有什么用?
当没有消息的时候在messagequeue的next方法里面有个nativePollOnce休眠了,调用quit然后退出了looper
7.既然可以存在多个 Handler 往 MessageQueue 中添加数据(发消息时各个 Handler 可能处于不同线程),那它内部是如何确保线程安全的?取消息呢?
答案见上文
8.我们使用 Message 时应该如何创建它?
obtain,享元机制,避免重复创建message导致内存抖动造成可能的oom
9.Looper死循环为什么不会导致应用卡死
loop无限循环用于取出消息并将消息分发出去,没有消息时会阻塞在queue.next()里的nativePollOnce()方法里,Android的绝大部分操作都是通过Handler机制来完成的,如果没有消息,则不需要程序去响应,就不会有ANR。ANR一般是消息的处理过程中耗时太长导致没有及时响应用户操作
乱七八糟的东西记录在后面
1.如果有个message需要立即处理怎么办。
调用这个方法他新建一个message没有target,
在看next()方法,他首先会循环遍历取出msg.target==null的msg进行处理
同步屏障的设置可以方便地处理那些优先级较高的异步消息。当我们调用Handler.getLooper().getQueue().postSyncBarrier() 并设置消息的 setAsynchronous(true) 时,target 即 为 null ,也就开启了同步屏障。当在消息轮询器 Looper 在 loop() 中循环处理消息时,如若开启了同步屏障,会优先处理其中的异步消息,而阻碍同步消息。屏幕点击的时候会使用,最后记得要移除同步屏障
2.子线程怎么创建handler
自己在线程里创建loop,然后调用handler = new handler(thread.loop),有问题,可能你线程的loop还没创建完就执行handler出错了,系统使用handlerthread完成了这个东西
当你使用getlooper的时候只能等上面的run方法执行完才能执行getlooper方法