Looper和Handler的分析
来源:互联网 发布:数据库产品有哪些 编辑:程序博客网 时间:2024/05/22 01:33
在写程序的时候我们经常用到handler来进行通信,但是却不太理解Handler的通信机制,今天有机会看了一下,下面来分析一下handler的机制。
看到Looper和handler就想起以前写程序的时候常用的几个方法Looper.prepare(),Looper.loop(),Handler的handleMessage(),就先从Looper.prepare()来分析:
以下是Looper.prepare()方法的源代码:
- private static void prepare(boolean quitAllowed) {
- if (sThreadLocal.get() != null) {
- throw new RuntimeException("Only one Looper may be created per thread");
- }
- sThreadLocal.set(new Looper(quitAllowed));
- }
这个方法非常简单,但是其中有一个sThreadLocal,不知道它是做什么的,那我们来找一下它的定义:
- static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
在Looper中只是new了一个ThreadLocal的对象,这个ThreadLocal是什么呢?网上查了一下
- 说ThreadLocal使得各线程能够保持各自独立的一个对象,并不是通过ThreadLocal.set()来实现的,而是通过每个线程中的new 对象 的操作来创建的对象,每个线程创建一个,不是什么对象的拷贝或副本。通过ThreadLocal.set()将这个新创建的对象的引用保存到各线程的自己的一个map中,每个线程都有这样一个map,执行ThreadLocal.get()时,各线程从自己的map中取出放进去的对象,因此取出来的是各自自己线程中的对象,ThreadLocal实例是作为map的key来使用的。
- private Looper(boolean quitAllowed) {
- mQueue = new MessageQueue(quitAllowed);
- mRun = true;
- mThread = Thread.currentThread();
- }
这个方法也很简单,只有两步1:创建一个MessageQueue对象。2:得到本线程的对象。
到目前为止Looper.prepare()方法已经执行完成,它都做了些什么呢?
1:创建一个Looper()对象,存入到ThreadLocal线程的局部变量中,每个线程只有一份。
2:创建了一个MessageQueue对象,用来保存消息
接着我们来分析一下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;
- // 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();
- 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);
- 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();
- }
- }
这个方法中其实有用的信息也就几行,下面我们首先来看第一行
- final Looper me = myLooper()
使用myLooper()方法得到了一个Looper()对象。其实就是从本线程的局部变量中将Looper对象拿出来。
- public static Looper myLooper() {
- return sThreadLocal.get();
- }
得到Looper对象之后,然后又从Looper对象中拿出来MessageQueue.最终调用for循环来遍历MessageQueue,从消息队列中拿出来待处理的消息。
- msg.target.dispatchMessage(msg);
然后我们再来看一下msg.target是什么?为什么要调用这个方法呢?在Message类的内部我们发现target的类型为Handler,所以这里应该是调用Handler的dispatchMessage()方法。
- public void dispatchMessage(Message msg) {
- if (msg.callback != null) {
- handleCallback(msg);
- } else {
- if (mCallback != null) {
- if (mCallback.handleMessage(msg)) {
- return;
- }
- }
- handleMessage(msg);
- }
- }
消息的处理流程大概就是以上的分析,但是我们还是没有分析handler的sendMessage()方法,别着急,下面我们就来看一下Handler的内部结构。
- 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 that has not called Looper.prepare()");
- }
- mQueue = mLooper.mQueue;
- mCallback = callback;
- mAsynchronous = async;
- }
这是Handler的构造方法,我们在其中来找到我们需要的信息,第一mLooper=Looper.myLooper(); 我们分析过Looper了,可知道这一行来得到线程局部变量ThreadLocal中保存的Looper对象,mQueue = mLooper.mQueue(); 这一句来得到Looper对象中的消息队列。
然后我们在分析Handler的sendMessage()方法。
- public final boolean sendMessage(Message msg)
- {
- return sendMessageDelayed(msg, 0);
- }
然后我们接着往下找
- public final boolean sendMessageDelayed(Message msg, long delayMillis)
- {
- if (delayMillis < 0) {
- delayMillis = 0;
- }
- return 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);
- }
这里来判断从Looper对象中拿到的消息队列是不是null,如果不是null,就执行enqueueMessage方法,这个方法一定就是把handler发送的消息放入消息队列的方法了。
到此为止,Handler和Looper发送和处理消息的流程我们就简单的分析完了。简单的说它的工作流程分为几步:
1.handler向本线程的消息队列中放入要处理的消息
2.Looper循环读取消息队列的消息,然后分配给相应的handler处理,Handler为构造Message是传入的Handler
3.Handler的handleMessage方法来处理相应的消息
由以上分析可知,handler和Looper都是使用的同一个消息队列。只有执行过Looper.prepare()和Looper.loop()方法的线程才可以使用Handler来发送处理消息。我们知道UI线程是可以使用Handler来发送消息的,那UI主线程一定也执行过这两个方法了。我们来看一看代码:
- public static void main(String[] args) {
- SamplingProfilerIntegration.start();
- // CloseGuard defaults to true and can be quite spammy. We
- // disable it here, but selectively enable it later (via
- // StrictMode) on debug builds, but using DropBox, not logs.
- CloseGuard.setEnabled(false);
- Environment.initForCurrentUser();
- // Set the reporter for event logging in libcore
- EventLogger.setReporter(new EventLoggingReporter());
- Security.addProvider(new AndroidKeyStoreProvider());
- Process.setArgV0("<pre-initialized>");
- Looper.prepareMainLooper();
- ActivityThread thread = new ActivityThread();
- thread.attach(false);
- if (sMainThreadHandler == null) {
- sMainThreadHandler = thread.getHandler();
- }
- AsyncTask.init();
- if (false) {
- Looper.myLooper().setMessageLogging(new
- LogPrinter(Log.DEBUG, "ActivityThread"));
- }
- Looper.loop();
- throw new RuntimeException("Main thread loop unexpectedly exited");
- }
只不过主线程中执行的是Looper.prepareMailLooper(),其实它和Looper.prepare()方法的作用是一样的。
- Looper和Handler的分析
- Looper和Handler的分析
- Android Looper和Handler分析
- Android Looper和Handler分析
- Android Looper和Handler分析
- Android Looper和Handler分析
- Android Looper和Handler分析
- Android Looper和Handler分析
- Android Looper和Handler分析 .
- Android Looper和Handler分析
- Android Looper和Handler分析
- Android Looper和Handler分析
- Android Looper和Handler分析
- Android Looper和Handler分析
- Android Looper和Handler分析
- Android Looper和Handler分析
- Android Looper和Handler分析 .
- Android Looper和Handler分析
- 数据库
- 一次有意思的错选执行计划问题定位(涉及SYS_OP_C2)
- 使用eclipse3.8搭建maven web开发环境,达到在eclipse编辑器中修改保存任何代码,都能直接启动tomcat预览效果的目的
- Android ViewDragHelper完全解析 自定义ViewGroup神器
- UIButton的一些属性和方法
- Looper和Handler的分析
- maven常用命令
- php嵌套js and html
- android 应用 kill ,restart ,重启,方法
- Parallels Desktop 如何使用键盘快捷键
- 使用TCP从客户端上传图片到服务器端
- 不错的视频教程列表
- linux grep命令详解
- Leetcode -- Find Median from Data Stream