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 是个完整的工具链,可以修改二进制应用.用户可以改装,安装,运行, ...
随机推荐
- LINUX - 通信
为什么三次握手: 让服务端和客户端都知道,自己的收信能力和发信能力没有问题: 第一次:客户端发给服务端--服务端知道了,自己的收信能力和客户端的发信能力没有问题: 第二次:服务端回复客户端--客户端知 ...
- Linux虚拟机封装成模板
对安装在VMware上的CentOS7.X进行封装,是为了后续的实验环境需要,可以批量去生成Linux系统.通过虚拟机模版来创建一台CentOS系统,跟原来机器一样,去掉了唯一性,而通过克隆出来的虚拟 ...
- Flow All In One
Flow All In One Flow is a static type checker for JavaScript https://github.com/facebook/flow https: ...
- SwiftUI render WKWebView
SwiftUI render WKWebView // // ContentView.swift // webview-app // // Created by 夏凌晨 on 2020/10/27. ...
- React.js vs Vue.js All in One
React.js vs Vue.js All in One React 与 Vue 区别对比 https://vuejs.org/v2/guide/comparison.html 1. 使用人数, 社 ...
- CSS style color all in one
CSS style color all in one https://developer.mozilla.org/en-US/docs/Web/CSS/color_value /* Hexadecim ...
- Headless Chrome Node API
puppeteer Headless Chrome Node API https://github.com/GoogleChrome/puppeteer https://pptr.dev/ PWA h ...
- how to write an ebook that can support published by format PDF, Epub, Mobi and so on
how to write an ebook that can support published by format PDF, Epub, Mobi and so on 如何写一本自己的电子书,支持各 ...
- js & replaceAll & non-global RegExp bug
js & replaceAll https://caniuse.com/#search=replaceAll https://developer.mozilla.org/en-US/docs/ ...
- Flutter FractionallySizedBox 设置维度比例 而不是固定的px
本周小部件 有时您的设计需要相对的维度. FractionallySizedBox允许您将子项的大小调整为总可用空间的一小部分. Scaffold( body: Center( child: Frac ...