handler+looper+messagequeue源码解析
https://www.jianshu.com/p/b4d745c7ff7a
handler机制源码
1.handler机制的作用
在多线程的场景中,将子线程中需要更新UI的操作信息传递到UI主线程。多个线程并发更新UI的同时 保证线程安全。
Message
线程间通信的数据单元(handler接受和处理的消息对象),存储需要操作的通信信息。
Message Queue
一种数据结构(先进先出)用来存储handler发过来的Message
Handler
主线程与子线程之间通信的媒介,线程消息的主要处理者.1、添加Message到MessageQueue中 2、处理Looper分派过来的Message.
Looper
MessageQueue与Handler之间的媒介,循环的取出MessageQueue里面的Message并分配给相应的Handler去处理。每个线程只能拥有一个Looper,但是一个Looper可以绑定多个线程的Handler
即:多个线程可以向同一个Looper管理的MessageQueue中发送Message。
handler发送消息的方式有2中
handler.sendMessage() 和 handler.post()
handler是怎样绑定线程的
一个handler只能绑定一个Looper对象,一个线程只能绑定一个Looper,但是一个Looper可以有多个handler,一个线程也可以有多个handler。
handler是通过绑定looper来绑定线程。
是通过Handler的构造方法来绑定Looper的
Looper的源码
prepare();
里面会调用prepare(true)方法
public static void prepare() {
prepare(true);
}
//去创建loopre对象
private static void prepare(boolean quitAllowed) {
//判断当前线程的loopre对象是否已经创建过 如果已经创建过就会抛出异常
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//真正的去创建looper对象,并放进sThreadLocal中
sThreadLocal.set(new Looper(quitAllowed));
}
//Looper的构造方法 创建Looper 和 MessageQueue的对象 和当前线程的引用
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
//获取当前线程的引用
mThread = Thread.currentThread();
}
//主线程创建Looper的方法并且从sThreadLocal获取这个对象
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
//从ThreadLocal中获取当前线程的looper对象
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
//获取主线程的looper对象
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
//获取当前线程的MessageQueue对象
public static @NonNull MessageQueue myQueue() {
return myLooper().mQueue;
}
//当前线程的引用是否是Looper所在的线程
public boolean isCurrentThread() {
return Thread.currentThread() == mThread;
}
//从开机到现在的毫秒数(手机睡眠的时间不包括在内)
final long now = SystemClock.uptimeMillis();
//当前消息的前一个消息
Message prevMsg = null;
//当前的消息
Message msg = mMessages;
//如果当前的消息不为空并且处理该消息的handler也不为空
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
Message的回收和复用:https://www.cnblogs.com/leipDao/p/7850473.html
//使用的是单链表的数据结构sPool指向链表的头部
private static Message sPool;
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
obtain()总结
好了,到此主要逻辑就分析完了,obtain()主要逻辑就是先判断缓存池中是否存在空闲message,
如果存在则返回头部message,并且指针指向下一个空闲message,
然后头部的message与之后链表 断开连接。如果不存在空闲message则直接new一个直接返回
上面的逻辑都是从缓存池中获取的操作,那什么时候向缓存池中存放呢?
public void recycle() {
if (isInUse()) {
if (gCheckRecycle) {
throw new IllegalStateException("This message cannot be recycled because it "
+ "is still in use.");
}
return;
}
recycleUnchecked();
}
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
recycle()最主要就是将当前message放入缓存池链表头部。
MessageQueue取出消息的原理: Message next() {}
nextPollTimeoutMillis:阻塞的时间 -1表示会一直阻塞,0表示不阻塞 其他时间为具体阻塞的时间
Handler是怎么发送消息到MessageQueue里面的,又是怎样处理消息的?
1.通过
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
public Handler() {
//第一个参数==null
this(null, false);
}
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
//此时这个值是空
mCallback = callback;
mAsynchronous = async;
}
public void handleMessage(Message msg) {
}
public interface Callback {
/**
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
public boolean handleMessage(Message msg);
}
可以看到在Handler创建的时候会绑定一个当前线程的Looper
在处理消息的时候:
public void dispatchMessage(Message msg) {
//如果msg.callback != null 标识是通过 handler.post(new Runnable() {}的方式发送消息的
if (msg.callback != null) {
handleCallback(msg);
} else {
否则就会回调我们的handleMessage方法。
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
否则就会回调我们的handleMessage方法。
handleMessage(msg);
}
}
handleCallback(msg); 就会执行下面的方法 进而回调我们的Run方法
private static void handleCallback(Message message) {
message.callback.run();
}
发送消息:
sendEmptyMessage(int what)
--->sendEmptyMessageDelayed(int what, long delayMillis)
--->sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
消息入队列
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
//最终会跑到MessageQueue中去处理
return queue.enqueueMessage(msg, uptimeMillis);
}
handler+looper+messagequeue源码解析的更多相关文章
- Android Handler机制(二)---MessageQueue源码解析
MessageQueue 1.变量 private final boolean mQuitAllowed;//表示MessageQueue是否允许退出 @SuppressWarnings(" ...
- Android Handler消息机制源码解析
好记性不如烂笔头,今天来分析一下Handler的源码实现 Handler机制是Android系统的基础,是多线程之间切换的基础.下面我们分析一下Handler的源码实现. Handler消息机制有4个 ...
- Android Handler机制(三)----Looper源码解析
一.Looper Looper对象,顾名思义,直译过来就是循环的意思,从MessageQueue中不断取出message. Class used to run a message loop for a ...
- Android Handler机制(四)---Handler源码解析
Handler的主要用途有两个:(1).在将来的某个时刻执行消息或一个runnable,(2)把消息发送到消息队列. 主要依靠post(Runnable).postAtTime(Runnable, l ...
- Android HandlerThread源码解析
在上一章Handler源码解析文章中,我们知道App的主线程通过Handler机制完成了一个线程的消息循环.那么我们自己也可以新建一个线程,在线程里面创建一个Looper,完成消息循环,可以做一些定时 ...
- Android源码解析——Handler、Looper与MessageQueue
本文的目的是来分析下 Android 系统中以 Handler.Looper.MessageQueue 组成的异步消息处理机制,通过源码来了解整个消息处理流程的走向以及相关三者之间的关系 需要先了解以 ...
- Android -- 从源码解析Handle+Looper+MessageQueue机制
1,今天和大家一起从底层看看Handle的工作机制是什么样的,那么在引入之前我们先来了解Handle是用来干什么的 handler通俗一点讲就是用来在各个线程之间发送数据的处理对象.在任何线程中,只要 ...
- Android -- AsyncTask源码解析
1,前段时间换工作的时候,关于AsyncTask源码这个点基本上大一点的公司都会问,所以今天就和大家一起来总结总结.本来早就想写这篇文章的,当时写<Android -- 从源码解析Handle+ ...
- Android 进阶16:IntentService 使用及源码解析
It's time to start living the life you've only imagined. 读完本文你将了解: IntentService 简介 IntentService 源码 ...
- Handler+Looper+MessageQueue深入详解
概述:Android中的异步处理机制由四部分组成:Handler+Looper+MessageQueue+message,用于实现线程间的通信. 用到的概念: Handler: 主要作用是发送消息和处 ...
随机推荐
- .NetCore中配置Ef
1.在NuGet中下载 Microsoft.EntityFrameworkCore.Tools Microsoft.EntityFrameworkCore.SqlServer 2.需要在Api层.实现 ...
- c# + appium 连接设备自动化
//private static AndroidDriver<AppiumWebElement> _driver; //private static AppiumLocalService ...
- 2020.4.2关于java.pta的总结
0.前言 本文是有关pta2020.3至2020.4所有面向对象程序课程(java)共三次作业的阶段性总结,是java学习最开始起步时期的成果. 1.作业过程总结 这三次作业,是从c++过渡到java ...
- 用for打印九九乘法表
package com.jiemo.struct;public class ForShabi4 { public static void main(String[] args) { //1.先打印第一 ...
- 关于Maven的使用
Maven基础入门 一.maven是什么 Apache Maven,是一个项目管理及自动构建的工具,有Apache软件基金会所提供. Maven是用Java语言编写的,是一款可以跨平台的软件. Mav ...
- 使用IDEA的webservice工具解析生成的客户端调用远程接口
由于这个接口的报文格式比较麻烦,是XML的请求头加上JSON格式的请求体,所以看起来比较复杂,也可以用RPC的方式调用,那样需要将请求头和请求体,响应头和响应体建实体.public JSONObjec ...
- 生产环境出现CPU占用过高,分析思路和定位
top 定位cpu占比高的pidjps -l 定位具体是后台哪个应用程序ps -mp 进程id -o(自定义格式) THREAD,tid,time 定位当前进程所有线程占用cpu时间高的线程idjst ...
- windows下查找端口、PID、查找进程、杀死进程
查找端口 netstat -ano|findstr "1099" TCP 0.0.0.0:1099 0.0.0.0:0 LISTENING 10120 TCP [::]:1099 ...
- 将map转成vo实体
//将map转成vo实体 AssetManagementProductsVO param= JSON.parseObject(JSON.toJSONString(map), AssetManageme ...
- KERNEL1
WHAT IS KERNEL KERNEL是一个负责连接计算机硬件与软件的一个模块,当软件对硬件进行调用的时候,或者发送一些置零的时候,KERNEL负责将这些指令转化并发送给CPU或者计算机中其他硬件 ...