Handler机制原理和常见问题

Handler机制原理和常见问题,第1张

Handler

用于处理消息,包括将发送消息到消息队列,和从消息队列中分发出去。

Message

用户对屏幕 *** 作而产生的信息。

Looper

一个死循环,不停地轮询等待线程给它的消息。

MessageQueue

存放消息的队列,是一个优先级队列,当新插入一个消息的时候,会先和队列内的消息的执行时间做对比,然后插入,执行时间越短,优先级越高,具体方法在enqueueMeassage()方法中。

首先可以把整个过程当成一个生产流水线,handler是机器手,message就是产品,messagequeue就是流水线的传输带,handler将message发送到传输带messagequeue上,message按照时间顺序排列在运输袋子上,looper就是发动机带动转轴,把message运输出去,最后又是handler把message分发出去。

具体的方法过程如下:

Handler首先调用sendMessage(),而sendMessage又调用MessageQueue的enqueueMessage()方法,该方法的目的是把message存在消息队列中。

现在消息已经在消息队列中了,需要一个动力去让这些消息被挨个的处理,于是我们就需要looper中的loop函数,它会调用queuenext()方法,这就取到了一个队列中的message,然后handler继续调用dispatchMessage()方法,该方法就包含了handler的handleMessage()方法,然后就会循环该过程。

1Looper如何停下来

当消息队列是空的时候,loop执行queuenext()的时候会阻塞,此时就可以停下来。

2一个线程中几个handler

随便多少个,new一个有一个。

3一个线程有几个looper

一个,由threadlocal决定。一个线程里面有一个threadlocalMap类型的变量,里面保存的是threadlocal,所以threadlocal是个key,value键值对,Looper的构造函数是个私有函数,只有在prepare()方法中初始化,在该方法中,set方法会获取当前线程,获取当前threadlocalMap,一个线程只对应一个map,map中一个key对应一个value,key是threadlocal,value就是Looper,所以一个线程绑定一个looper。

4Handler为什么会内存泄漏,解决方案

Handler持有Activity。因为handler是个匿名内部类,可以持有外部类对象,所以handler持有activity。内存泄漏和handler的机制有关,message持有handler,handler又持有activity,message又有延迟处理的情况,所以会一直存在消息队列中,这时候messageQueue又持有activity,只要message不及时处理,activity就不会被回收。解决方案是:activity弱引用。

5为什么在主线程中可以直接new handler

当启动app的时候,会先启动Luncher,然后在linux层,会调用zygote去给每个应用建立一个虚拟机,此时会调用activityThread再去使用main方法,里面就有prepareMainLooper方法,此时可以知道所有组件都是围绕主线程looper,以消息存在。

6怎么在子线程中new一个handler

先Looperprepare(),在new handler,最后Looperloop()

7子消息Looper,没有消息怎么办

消息队列没有消息,会调用nativePollOnce方法,这个方法会进去等待状态,此时会调用linux的epoll函数并传入-1,epoll函数会将结果传入linux的消息队列中,若这个值是-1,则会陷入永久等待状态,线程挂起。

8 Looper怎么退出

调用messageQueuequit方法,这个过程中,首先removeAllmessageLocked(),把所有的消息全部移出去。此时调用了recycleUnchecked()方法,将消息内部变量赋值为null,然后调用nativeWake(),这个和epoll相反,它唤醒了线程,并返回一个为null的msg,Loop中for循环就会终止。

9主线程需要释放looper吗

不能,AMS围绕handler管理,四大组件也是靠主线程的Looper处理 *** 作

10多个handler往消息队列放消息怎么保证线程安全

加锁,使用synchronized

11怎么生成一个message

使用享元设计模式,提前已经存在了一个消息队列,已经处理完的消息,会被赋值为null,并且用头插法存在这个列表中。当使用obtain的时候会从该消息队列中获取一个空消息

12Looper为何不会让应用卡死

二者之间,ANR的原因是消息没有被及时处理,而looper没有消息时候会进入睡眠状态释放线程。

首先,Handler,Looper,MessageQueue这三者如何关联的?这里拿最简单的new 一个无参Handler为例。在创建无参的Handler时会对其中变量MessageQueue赋值,这个值就是Looper对象的MessageQueue,那么这个Looper对象又是在那创建的呢?如果是在app进程中的话,在启动该app时会调用ActivityThread,main方法进入主线程,在main函数中会有初始化Looper,并调用looperloop()轮询MessageQueue中的Message,这个Message是handler在调用sendMessage或者post时会将Message enqueue到MessageQueue中,这样Looper 就会loop 到Handler发送到MessageQueue中的Message,loop时就会dispatchMessage了,再然后就是Hanlder处理message了,在调用sendMessage时,handler必须要重写handleMessage方法。这样就完成了发送消息和处理消息。在app的进程中,thread1还是发送消息到主线程中的MessageQueue,这个MessageQueue在首次启动app时就在创建Looper时已经创建好了。那么如果不是在app进程怎么办呢?假如是在ActivityManagerService中使用Handler的话呢?ActivityManagerService可以理解为在system_server进程中的一个线程,在启动system_server时并没有像启动一个app进程那样系统已经创建好了Looper,那么咱们如果要使用Handler机制,就必须要有Handler,Looper,MessageQueue,Messag,另外,系统也已经封装好了,就是HandlerThread。HandlerThread是一个Thread,在里面已经将Looper,MessageQueue准备好了,这时候创建Handler时,将HandlerThread的Looper传给Handler就行了,这样Handler,Looper,MessageQueue就都有了,就可以利用Handler机制进行线程间通信了。

new Handler(LoopergetMainLooper())由getMainLooper()可知是获取UI主线程looper,在UI线程中处理消息;

Handler handler = new Handler()会默认用当前线程的looper,一般情况是当前线程的异步线程与当前线程进行消息处理。

一般而言new Handler(LoopergetMainLooper())用于更新UI,Handler handler = new Handler()用于当前线程与异步线程的消息处理

以上就是关于Handler机制原理和常见问题全部的内容,包括:Handler机制原理和常见问题、Android在子线程用handler发送的消息,主线程是怎么loop到的、Handler handler = new Handler()和new Handler(Looper.getMainLooper())的区别等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/9451433.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-28
下一篇2023-04-28

发表评论

登录后才能评论

评论列表(0条)

    保存