| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 移动开发 -> Android中Handler知识(一) -> 正文阅读 |
|
[移动开发]Android中Handler知识(一) |
Handler、Looper、Message?篇幅较长 Handler。
首先,我们创建两个Handler对象。这边我们一个在主线程中实例,一个放在线程中实例:
此时会发现在线程中创建的Handler对象会崩溃,错误信息是:Can't create handler inside thread that has not called Looper.prepare() 根据提示,我们没有使用Looper.prepare();我们添加此行代码调试:
我们发现不崩溃了。此时会有疑问,为什么会出现这样的问题呢?我们来跟跟源码,从构造函数开始:
构造函数中只是简单调用了this函数,我们继续跟踪this函数
可以看出在此函数中 mLooper为空时,抛出次异常。那什么时候为空呢,继续跟踪myLooper();
我们在这个方法中就会有疑问了,sThreadLocal是啥?作用是干嘛的。我们先看类中sThreadLocal的申明:
可以简单的看成是Looper的一个集,若sThreadLocal变量存在Looper对象,就可以被get()到,否则返回null。跟踪到这边我们大概可以猜到Looper.prepare()做啥了,去设置sThreadLocal;来看看源码:
到这边'为什么要prepare再创建'就结束了。但我们的好奇心会问了:为什么主线程不需要我们先perpare再创建? 为什么主线程不需要我们先prepare再创建主线程不需要prepare的原因是:提前已经给我们处理过了这个问题。我们查看ActivityThread中的main()方法:
在此方法中我们能看到执行了Looper.prepareMainLooper();这个方法做什么用呢?我们继续跟踪:
我们看到在此方法中执行了prepare()。 发送信息接下来我们来了解一下怎么发送消息。流程是创建一个Message->给Message对象设置值->借助Handler发送。
发送后我们再利用Handler中的handleMessage()方法这个Message拿出来使用即可。但内部具体流程是怎么样的,我们一起来分析一下源码。从发送方法开始sendMessage()。源码太长有些方法会直接介绍作用,有兴趣的可自己去看源码 入队操作
由sendMessageAtTime()分析得出,Message对象创建一个消息队列MessageQueue,它由mQueue赋值,源码中mQueue = mLooper.mQueue,而mLooper是Looper对象,由最上面介绍Handler时有介绍,每个线程只有一个Looper,因此,相应的Looper对应相应的MessageQueue。之后enqueueMessage(queue, msg, uptimeMillis)是入队操作。
观察方法内代码,队列中根据时间when来排序,这个时间就是我们一路传过来的参数,之后再根据时间顺序调用msg.next来指定下一个要处理的消息是什么,如果通过sendMessageAtFrontOfQueue()中也是通过enqueueMessage(queue, msg, 0)进行入队,不过它没有设置延时时间,此时Message会直接添加到对头。入队到这边就了解差不多了,接下来是出队操作。 出队操作我们队列MessageQueue对象是在Looper中赋值,所以可直接在Looper类中找出队操作。来看一看Looper.Loop()方法:
代码过多,只挑重要的分析,进入for死循环,之后不断从MessageQueue对象中取出消息msg,next()就是进行队列的出队方法,next()方法代码有点长,这边就不贴出来了。next的主要逻辑是:判断当前MessageQueue是否存在待处理的mMessages消息,如果有,就出队此消息,然后让下一个消息成为mMessages,否则就进入阻塞状态,一直等到有新的消息入队唤醒。回看loop方法,在执行next()方法后会执行msg.target.dispatchMessage(msg);,此时msg.target就是Handler对象,最后看一下dispatchMessage()方法:
如果mCallback 不为null则调用mCallback.handleMessage(),否则调用handleMessage(),并将消息作为参数传出去。这样我们就明白为什么要使用handleMessage()来捕获我们之前传递过去的信息。 根据上面的理解,不难写出异步消息处理机制的线程。
总结Looper负责创建一个消息队列MessageQueue对象,然后进入死循环中不断的取出消息,这些消息都是由一个或者多个Handler进行创建处理的。 |
|
移动开发 最新文章 |
Vue3装载axios和element-ui |
android adb cmd |
【xcode】Xcode常用快捷键与技巧 |
Android开发中的线程池使用 |
Java 和 Android 的 Base64 |
Android 测试文字编码格式 |
微信小程序支付 |
安卓权限记录 |
知乎之自动养号 |
【Android Jetpack】DataStore |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/23 17:21:53- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |