网站建设技术 翻译,哪个网站的品牌特卖做的好,微信抽奖小程序制作,wordpress tag页面目录
为什么会有HandlerHandler的原理#xff0c;以及对象讲解主线程的loop在哪里#xff0c;为什么主线程loop没有阻塞呢#xff1f;Looper如何保证唯一Handler为什么会引发内存泄漏呢#xff1f;Message应该如何创建它#xff1f;
一、为什么会有Handler 线程分为主线…目录
为什么会有HandlerHandler的原理以及对象讲解主线程的loop在哪里为什么主线程loop没有阻塞呢Looper如何保证唯一Handler为什么会引发内存泄漏呢Message应该如何创建它
一、为什么会有Handler 线程分为主线程(主线程又叫UI线程和子线程主线程即ActivityThread规定只有此线程能操作UI但我们从后台请求数据都是在子线程操作所以需要有人帮忙把线程切换一下所以就有了Handler。
二、Handler的原理以及对象讲解 2.1 它是如何子线程和主线程通知 我们来看看Handler的最最最初的实现。主线程和子线程子线程的数据需要通知到主线程去主线程拿到数据以后就去调用方法去更新UI。那么我们想想如果你去实现子线程通知主线程也就是两个线程之间通讯那么你会使用什么方法 使用全局变量共享成员比如
//这里只是简单的介绍了一下
var flag:Boolean false
Thread(object :Runnable{override fun run() {if (flag) {//调用通知UI更新的方法}}}).start()Thread(object :Runnable{override fun run() {flag true}}).start()如下sendMessage就是上面的一个变化通知当收到新消息的时候则会回调handleMessage方法进行操作。 handler.sendMessage(uimsg);final Handler handler new Handler() {Overridepublic void handleMessage(Message msg) {getMessage(msg);}
};2.2 对象讲解loopermessagemessagequeue Handler当然没有我们上面说的那么简单只是我们拆开了最初的原理。接下来我们再讲一下Looper对象我们可以注意到我们写的最初的线程执行完就结束了那么肯定不能结束呀对吧因为他要继续监听消息。所以呢还应该进行如下这样的改进让它不断的循环
var flag:Boolean falseThread(object :Runnable{override fun run() {while (run){if (flag) {//调用通知UI更新的方法}}}}).start()Thread(object :Runnable{override fun run() {flag true}}).start()而对应到HandlerLooper就是做这个事情的我们可以看看源码就会有一个循环不断的循环处理消息 因为消息很多(message)所以我们会有一个MessageQueue通道来进行管理、传输以及通知。
消息来了以后loop收到以后开始发送loop有一个for循环的功能。这里注意一个问题loop是已经开始运转了还是收到消息才开始启动呢 没错是已经运转了。线程一开启就立马启动了。上面的例子我们可以看到for已经循环了。
我们可以看看调用handleMessage的源码 looper在循环如果有数据则开始调用回调而通知的方法则在handler里面。
源码的主要方法调用 流程示意图 2.3 这里有一个疑问loop是如何知道线程是谁的queue又是谁的。 直接在handler里面创建了looper所以就知道是谁的了。 而queue则是在looper里面创建的。 三、主线程的loop在哪里为什么主线程loop没有阻塞呢 主线程的loop在哪里在main方法ActivityThread里面 我们可以注意到主线程也不会结束mian方法也有一个loop循环。 为什么主线程loop没有阻塞呢但我们看到其实他还是阻塞的不阻塞程序就运行完成了。只不过他是如何阻塞的他是有数据刷新才运行没有数据刷新就阻塞让出cpu所以他采用的队列、epoll阻塞去执行其他的任务比如刷新ui。 四、Looper如何保证唯一 一个线程只能有一个loop不可能有多个因为你调用了looper的loop,后面的代码就不会执行了。 调用两次prepare会崩溃为什么会崩溃呢因为一个线程只能有一个looper源码里面直接报错了 判断有没有值。有直接报错没有就往下执行。这就是它的执行方式。
五、Handler为什么会引发内存泄漏呢 Handler是内部类内部类持有外部类的引用。但为什么其他内部类就可以呢持有链。长生命周期持有短生命周期的引用就会导致无法被释放。
5.1 持有链
首先我们先想想哪个对象不可能被释放 没错主线程对象。然后主线程对象持有looper而looper持有messagequeue,而messagequeue持有messagemessage是一个链表而message又持有hander而handler又持有activity所以长生命周期持有短生命周期activity那么页面切换activity就无法得到释放。 六、Message应该如何创建它 为什么用2呢这里要了解一下内存抖动。用第一种会导致创建大量的对象并销毁对象就是内存抖动。如下这种就是内存抖动。 解决内存抖动的根本方法就是内存复用对象复用。所以我们要调用obtain方法。message是一个链表存储着message进行复用。 这里的spool就是一个message。如果你直接new message,那么每次都是一个新的链表而使用Message的obtain方法,它会进行复用。