android分析之消息处理
前序:每个APP对应一个进程,该进程内有一个ActivityThread的线程,称为主线程(即UI主线程),此外,还有其他线程,这个再论。
android的消息系统分析。
- 每个Thread只对应一个Looper
- 每个Looper只对应一个MessageQueue
- 每个MessageQueue中有N个Message
- 每个Message中最多指定一个Handler来处理事件
- 一个Thread可以对应多个Handler
Looper负责从消息队列中(MessageQueue)取出消息(Message/Runnable),交给Handler来处理。
Message:
public final class Message implements Parcelable {
public int what;//每个Message可以指定一个Handler,由于可以存在多个Handler,用what来标识具体的Handler public int arg1;
public int arg2;
public Object obj;
public Messenger replyTo; /*package*/ static final int FLAG_IN_USE = 1 << 0; /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1; /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE; /*package*/ int flags; /*package*/ long when; /*package*/ Bundle data; /*package*/ Handler target;//指定由哪个Handler来处理本Message /*package*/ Runnable callback; /*package*/ Message next;//消息链 private static final Object sPoolSync = new Object();
private static Message sPool;//消息链表的头,注意是static
private static int sPoolSize = 0; private static final int MAX_POOL_SIZE = 50;
......
}
MessageQueue实际上是对Message的一种操作的封装,真正的消息队列是以sPool为首的消息链表:
public class MessageQueue {
// True if the message queue can be quit.
private final boolean mQuitAllowed; @SuppressWarnings("unused")
private int mPtr; // used by native code Message mMessages;//消息...
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
private IdleHandler[] mPendingIdleHandlers;
private boolean mQuiting; // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
private boolean mBlocked; // The next barrier token.
// Barriers are indicated by messages with a null target whose arg1 field carries the token.
private int mNextBarrierToken;
//调用Native函数做真正的处理
private native void nativeInit();
private native void nativeDestroy();
private native void nativePollOnce(int ptr, int timeoutMillis);
private native void nativeWake(int ptr);
......
}
Looper:
public class Looper {
private static final String TAG = "Looper"; static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();//与线程相关的模板类
private static Looper sMainLooper; //static类型,只有一个 final MessageQueue mQueue;//Looper持有的MessageQueue
final Thread mThread;
volatile boolean mRun; private Printer mLogging;
......
}
Handler:
public class Handler{//真正对处理Message的类:包括处理Message和将消息压到MessageQueue队列里 final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
IMessenger mMessenger; ... }
Looper的loop()循环:
public static void loop() {
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; Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity(); for (;;) {//消息循环
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
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
} msg.target.dispatchMessage(msg);//调用消息指定的接收者Handler来处理它 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.recycle();//丢弃消息,循环再利用
}
}
Handler取消息,每次从sPool(Message里的static Message类型)取出一个Message,其调用的是static方法:
public static Message obtain(Handler h, int what, Object obj) {
Message m = obtain();
m.target = h;
m.what = what;
m.obj = obj; return m;
}
Handler将消息压入消息队列:
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
{
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this;
sent = queue.enqueueMessage(msg, uptimeMillis);//调用MessageQueue的方法执行压入操作
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}
小结:Handler取消息是直接取(从sPool里),将消息压入MessageQueue是调用MessageQueue的方法。
----------------------------------------------分割线----------------------------------------------------------------------------
下面分析这些对象都是在什么时候创建的。
Looper是什么时候创建的?
每个线程都只有一个Looper对象。
1.普通线程(非主线程)
一个典型的自己创建的线程使用Looper如:
class LooperThread extends Thread{
public Handler mHandler;
public void run(){
Looper.prepare();
mHandler= new Handler(){
public void handleMessage(Message msg){
//处理消息
}
};
Looper.loop();//进入消息循环
}
}
那么Looper是在什么时候创建的呢?看Looper.prepare()方法:执行完这个方法,就得到了一个本线程独有的Looper。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();//这是一个与线程先关的模板类
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {//若调用者所在宿主线程已经有Looper,则抛出异常
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));//Java中的线程局部存储,即不同线
}//程都通过sThreadLocal得到自己的不同的Looper对象引用
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);//创建Looper要处理的消息队列
mRun = true;
mThread = Thread.currentThread();//得到当前线程
}
那么Handler是如何与Looper关联起来的呢?看Handler的构造方法:
public Handler() {
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();//通过线程局部存储,获得本线程的Looper
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = null;
}
public static Looper myLooper() {//获取与本线程相关的Looper
return sThreadLocal.get();
}
小结:每个线程都通过sThreadLocal<Looper>来创建一个Looper(进而创建一个MessageQueue),再创建一个Handler(通过sThreadLocal),从而将Handler与Looper“绑定”在一起,形成一个完整的消息循环系统。
2.主线程ActivityThread
主线程是什么时候创建Looper的?在ActivityThread.java的main方法里有:
public static void main(String[] args) {
SamplingProfilerIntegration.start();
CloseGuard.setEnabled(false); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper();//也是sThreadLocal.set(new Looper(quitAllowed))来创建一个线程所属的Looper,并通过sThreadLocal.get()将Looper赋给sMainLooper(private static Looper sMainLooper),sMainLooper的作用就是,其他线程可以获取到主线程的Looper(因为sMainLooper是static,在主线程中赋值的)。
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
} ActivityThread thread = new ActivityThread();
thread.attach(false); AsyncTask.init(); if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
} Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited");
}
Looper.loop()是一个static的方法,作为消息循环处理器,不断的取消息,分发消息。
android分析之消息处理的更多相关文章
- 从Handler+Message+Looper源代码带你分析Android系统的消息处理机制
PS一句:不得不说CSDN同步做的非常烂.还得我花了近1个小时恢复这篇博客. 引言 [转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树] 作为A ...
- Android应用程序消息处理机制(Looper、Handler)分析
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6817933 Android应用程序是通过消息来 ...
- Android多线程----异步消息处理机制之Handler详解
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...
- Android应用程序消息处理机制笔记
看老罗的Android源码情景分析学习的时候,边抄边理解再总结.希望能为面试提供点帮助吧. 1.Android应用程序是通过消息来驱动,Android应用程序每一个线程在启动时,都可以首先在内部创建一 ...
- Android Handler 异步消息处理机制的妙用 创建强大的图片加载类(转)
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38476887 ,本文出自[张鸿洋的博客] 最近创建了一个群,方便大家交流,群号: ...
- android分析windowManager、window、viewGroup之间关系(一)
本文将主要介绍addview方法,在windowManager.window.viewGroup中的实现原理.首先将介绍这些类结构关系,然后分析其内在联系,介绍实现原理,最后介绍重要的一个参数wind ...
- Android Handler 异步消息处理机制的妙用 创建强大的图片载入类
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38476887 ,本文出自[张鸿洋的博客] 近期创建了一个群.方便大家交流,群号: ...
- Android之Handler消息处理机制
Handler的作用 Handler消息机制在Android中的应用非常广泛,很多组件的底层实现都是靠Handler来完成的,所以掌握Handler消息机制的原理还是非常重要的.Handler的主要功 ...
- Android 分析工具 APKAnalyser
APKAnalyser 是 Android 静态,虚拟分析工具,用来测试和验证 Android 应用的开发工作.ApkAnalyser 是个完整的工具链,可以修改二进制应用.用户可以改装,安装,运行, ...
随机推荐
- 网络之一次http请求的完整过程
关于网络的知识平时可能真正用的比较少,但是有一些点还是需要总结的: 完成一次http请求要大致可以分为7个步骤: 一.TCP三次握手 第一次握手:建立连接.客户端发送连接请求报文段,将SYN位置为1, ...
- 一道思维题 &&递归改循环
思路: 比如5 2 12345--> 1245 从3开始,这时候5变成了1.剩下4512,对应1234.只需要找到现在n-1,k中的数对应原来的编号的映射. 比如1-->3 是1+2 mo ...
- Leetcode(868)-二进制间距
给定一个正整数 N,找到并返回 N 的二进制表示中两个连续的 1 之间的最长距离. 如果没有两个连续的 1,返回 0 . 示例 1: 输入:22 输出:2 解释: 22 的二进制是 0b10110 . ...
- Prometheus Monitoring Solution
Prometheus Monitoring Solution 普罗米修斯 https://prometheus.io/ 警报 监控 增强指标和警报 领先 开源监控解决方案 https://promet ...
- free video tutorial of Deep Learning
free video tutorial of Deep Learning AI 深度学习/ 机器学习/人工智能 Deep Learning With Deep Learning – a form of ...
- vue农历日历
<template> <div class="calendar-main"> <div class="choose_year"&g ...
- VAST上线后,如何提升NGK算力生态的收益和流动性?
自比特币诞生以来,"挖矿"一词就成功地步入了大众的视野,也成为了加密货币领域最重要的组成部分之一.无论是早前基于比特币和以太坊为主的算力挖矿,还是逐步进入大众视野的质押挖矿,亦或是 ...
- 阿里面试这样问:redis 为什么把简单的字符串设计成 SDS?
2021开工第一天,就有小伙伴私信我,还给我分享了一道他面阿里的redis题(这家伙绝比已经拿到年终奖了),我看了以后觉得挺有意思,题目很简单,是那种典型的似懂非懂,常常容易被大家忽略的问题.这里整理 ...
- C++算法代码——卡片游戏
题目来自:http://218.5.5.242:9018/JudgeOnline/problem.php?cid=1397&pid=2 题目描述 桌上有一叠牌,从第一张牌(即位于顶面的牌)开始 ...
- 使用 Castle 实现 AOP,以及 Autofac 集成 Castle
Castle 是 2003 年诞生于 Apache Avalon 项目,目的是为了创建一个IOC 框架.发展到现在已经有四个组件: ORM组件:ActiveRecord IOC组件:Windsor 动 ...