Looper 源码分析
//可以看到我们的Looper是存放在线程独有的ThreadLocal进行隔离的
//也就是每个线程独有一份Looper
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
//系统帮我们实现的主线程的Looper对象
private static Looper sMainLooper;
//每一个Looper都有自己的MessageQueue消息队列
final MessageQueue mQueue;
final Thread mThread;
* class LooperThread extends Thread {
* public Handler mHandler;
*
* public void run() {
* Looper.prepare();
*
* mHandler = new Handler() {
* public void handleMessage(Message msg) {
* // process incoming messages here
* }
* };
*
* Looper.loop();
* }
* }
这个是Looper开篇的使用示例
我们在使用Handler机制的时候需要创建一个Looper对象利用Looper里面的MessageQueue消息队列
来存放我们发送的Message消息Message消息里面存有我们发送的数据、延迟时间、回调方法等。
这样在looper进行轮询消息队列的时候就能够将里面的Message交给对应的Handler去处理。
在子线程中:
Looper.prepare();是用来创建一个Looper的
源码:
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
//从ThreadLocal去拿我们的Looper 如果已经存在了就抛出异常
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//否则就创建一个looper对象并放在ThreadLocal中存储
sThreadLocal.set(new Looper(quitAllowed));
}
new Looper(quitAllowed) 源码:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
可以看到 在创建Looper的时候也会创建一个MessageQueue消息队列
//主线程的Looper创建----系统会在ActivityThread的main()方法里面调用这个方法进行创建的
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
* 源码分析:main()
**/
public static void main(String[] args) {
Looper.prepareMainLooper();
// 1. 为主线程创建1个Looper对象,同时生成1个消息队列对象(MessageQueue)
// 方法逻辑类似Looper.prepare()
// 注:prepare():为子线程中创建1个Looper对象
ActivityThread thread = new ActivityThread();
// 2. 创建主线程
Looper.loop();
// 3. 自动开启 消息循环 ->>下面将详细分析
}
loop() 源码
public static void loop() {
//获取当前线程的Looper对象
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
// Allow overriding a threshold with a system prop. e.g.
// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
final int thresholdOverride =
SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
+ ".slow", 0);
boolean slowDeliveryDetected = false;
for (;;) {
// 从MessageqQueue里面去拿消息 这个过程会随着message取完后阻塞
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long traceTag = me.mTraceTag;
long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
if (thresholdOverride > 0) {
slowDispatchThresholdMs = thresholdOverride;
slowDeliveryThresholdMs = thresholdOverride;
}
final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
final boolean needStartTime = logSlowDelivery || logSlowDispatch;
final boolean needEndTime = logSlowDispatch;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
try {
//取出的消息会交给对应的Handler去处理
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logSlowDelivery) {
if (slowDeliveryDetected) {
if ((dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
slowDeliveryDetected = false;
}
} else {
if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
msg)) {
// Once we write a slow delivery log, suppress until the queue drains.
slowDeliveryDetected = true;
}
}
}
if (logSlowDispatch) {
showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
//释放这个消息 放入消息缓冲池---单链表的头部
msg.recycleUnchecked();
}
}
总结:Looper实际是利用ThreadLocal和线程进行绑定的,通过内部维护的一个消息队列来存储格格Handler发送过来的Message
实现线程间通信的
Looper 源码分析的更多相关文章
- 【Android】Handler、Looper源码分析
一.前言 源码分析使用的版本是 4.4.2_r1. Handler和Looper的入门知识以及讲解可以参考我的另外一篇博客:Android Handler机制 简单而言:Handler和Looper是 ...
- Handle/Looper源码分析;
1. Handle中的属性: final Looper mLooper; final MessageQueue mQueue; final Callback mCallback; final bool ...
- Handler、Looper、MessageQueue、Thread源码分析
关于这几个之间的关系以及源码分析的文章应该挺多的了,不过既然学习了,还是觉得整理下,印象更深刻点,嗯,如果有错误的地方欢迎反馈. 转载请注明出处:http://www.cnblogs.com/John ...
- Android Handler处理机制 ( 一 )(图+源码分析)——Handler,Message,Looper,MessageQueue
android的消息处理机制(图+源码分析)——Looper,Handler,Message 作为一个大三的预备程序员,我学习android的一大乐趣是可以通过源码学习 google大牛们的设计思想. ...
- Android源码分析-消息队列和Looper
转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/17361775 前言 上周对Android中的事件派发机制进行了分析,这次博主 ...
- Android消息机制源码分析
本篇主要介绍Android中的消息机制,即Looper.Handler是如何协同工作的: Looper:主要用来管理当前线程的消息队列,每个线程只能有一个Looper Handler:用来将消息(Me ...
- Android7.0 Phone应用源码分析(二) phone来电流程分析
接上篇博文:Android7.0 Phone应用源码分析(一) phone拨号流程分析 今天我们再来分析下Android7.0 的phone的来电流程 1.1TelephonyFramework 当有 ...
- Robotium源码分析之Instrumentation进阶-attach
在分析Robotium的运行原理之前,我们有必要先搞清楚Instrumentation的一些相关知识点,因为Robotium就是基于Instrumentation而开发出来的一套自动化测试框架.鉴于之 ...
- Robotium源码分析之Instrumentation进阶
在分析Robotium的运行原理之前,我们有必要先搞清楚Instrumentation的一些相关知识点,因为Robotium就是基于Instrumentation而开发出来的一套自动化测试框架.鉴于之 ...
- Android7.0 Phone应用源码分析(三) phone拒接流程分析
本文主要分析Android拒接电话的流程,下面先来看一下拒接电话流程时序图 步骤1:滑动按钮到拒接图标,会调用到AnswerFragment的onDecline方法 com.android.incal ...
随机推荐
- 2003031126-石升福-Python数据分析-五一假期作业
项目 内容 班级链接 20级数据班(本) 作业链接 五一假期作业 博客名称 2003031126-石升福-Python数据分析-五一假期作业 要求 每道题要有题目,代码(使用插入代码,不会插入代码的自 ...
- Hspui的使用,NJUPT
一.打开Hspui,进入UI界面 二.添加.sp文件 File->Open打开想要仿真的文件 三.运行仿真 点击Simulate 四.观察结果 点击Waveview进入波形观察器 选中目录下要观 ...
- Windows10常用快捷键总结
--Windows10常用快捷键总结 1. Window键: 打开或关闭|开始菜单 2. Win + A 打开操作中心 3. Win + D 显示桌面 4. Win + E 打开计算机文件管理器 5. ...
- 1004 Counting Leaves (30分)
今天在热心网友的督促下完成了第一道PAT编程题. 太久没有保持训练了,整个人都很懵. 解题方法: 1.读懂题意 2.分析重点 3.确定算法 4.代码实现 该题需要计算每层的叶子节点个数,所以选用BFS ...
- Angular Material TreeTable Component 使用教程
一. 安装 npm i ng-material-treetable --save npm i @angular/material @angular/cdk @angular/animations -- ...
- PYinstall打包程序出现编码错误的解决 'utf-8' codec can't decode byte 0xce in position 171: invalid continuation b
网上说,先执行,再打包 chcp 65001 试过没有用. 解决方案: 把import的包批量注释,然后寻找是import那个文件导致. 虽然注释会导致程序运行出错,但是打包才不管你能不能运行. 最后 ...
- mock数据规则
Mock数据规则 随机生成100条内的list数据 let Mock = require("mockjs"); let basicData = Mock.mock({ " ...
- Qt非主线程显示窗口的简易思路
首发于我的个人博客:xie-kang.com 博客内有更多文章,欢迎大家访问 原文地址 Qt 在非主线程是无法显示UI窗口的,如果我们在其它线程中处理完数据,需要使用窗口展示,或者在其它线程需要使用到 ...
- 适用于 Linux 的 Windows 子系统使用 Visual Studio Code
在WSL中使用VS Code,先在Windows中安装vscode,再通过功能扩展安装Vscode for wsl. VSCode 有system和user两个版本,默认下载链接为user版本.以下内 ...
- Python学习笔记--循环的知识以及应用
while循环 代码: 结果: 案例:求1-100的和 实现: 案例:while循环猜数字 实现: while循环的嵌套使用 案例:打印九九乘法表 (注意:要是想要输出不换行,代码可以这样写:prin ...