解析Hander消息处理机制
来源:互联网 发布:聊天气泡软件 编辑:程序博客网 时间:2024/04/26 21:01
本篇主要讲述Hander源码解析
首先我们new Hander点进去看看它的构造方法,
/** * Default constructor associates this handler with the {@link Looper} for the * current thread. * * If this thread does not have a looper, this handler won't be able to receive messages * so an exception is thrown. */ public Handler() { this(null, false); }
调用了两个参数的,我们在往下看:
/** * Use the {@link Looper} for the current thread with the specified callback interface * and set whether the handler should be asynchronous. * * Handlers are synchronous by default unless this constructor is used to make * one that is strictly asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with respect to synchronous messages. Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. * * @param callback The callback interface in which to handle messages, or null. * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. * * @hide */ 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; }
mQueue = mLooper.mQueue; 得到的是一个消息队列
mCallback = callback;是消息处理了一个回调
mAsynchronous = async;设置消息是否是异步的
/** * Return the Looper object associated with the current thread. Returns * null if the calling thread is not associated with a Looper. */ public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
以上就是Hander了构造方法了;
我们在看下这个异常,当mLooper==null的时候就会抛出下面这段话,
if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); }
而mLooper又是通过 sThreadLocal.get()这个方法返回的;
那么这个sThreadLocal.get()是在哪里赋值的呢?
根据异常信息我们可以看到"无法在未调用Looper.prepare()的线程中创建处理程序"
大白话就是没有调用Looper.prepare()这个方法, 接下来我们就看看这个方法
/** Initialize the current thread as a looper. * This gives you a chance to create handlers that then reference * this looper, before actually starting the loop. Be sure to call * {@link #loop()} after calling this method, and end it by calling * {@link #quit()}. */ public static void prepare() { prepare(true); } 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.set(new Looper(quiAllowed));
所以我们用Hander之前要调用一下Looper.prepare()这个方法,接下肯定会有人疑惑为什么在主线程的没调用这个方法也可以直接使用Hander呀!!! 不急, 我们在看下ActivityThread中的main()方法:
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); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); if (sMainThreadHandler == null) { sMainThreadHandler = new Handler(); } ActivityThread thread = new ActivityThread(); thread.attach(false); if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); } }
我们可以看到系统调用了一个Looper.prepareMainLooper()方法,我们在点进去看一下:
public static final void prepareMainLooper() { prepare(); setMainLooper(myLooper()); if (Process.supportsProcesses()) { myLooper().mQueue.mQuitAllowed = false; }}
我们之所以能够在主线程中直接使用Hander原来系统已经默认帮我们调用prepare()这个方法,因此我们应用程序的主线程中会始终存在一个Looper对象,从而不需要再手动去调用Looper.prepare()方法了。而子线程中我们要使用Hander就必须自己手动调用一下Looper.prepare()方法了,
当Looper.prepare()走完以后接下来就会走Looper.loop()这个方法,我们在看下:
Looper.loop()的源码
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the 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 final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } final long traceTag = me.mTraceTag; if (traceTag != 0) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } try { msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } 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(); } }
上面的源码只要是就说明
先通过 final MessageQueue queue = me.mQueue; 得到一个消息队列
下面在一个for(;;)的死循环,
在通过queue.next();这个方法不停走消息队列里面获取消息
msg.target.dispatchMessage(msg); 这个方法将消息发送出去 msg.target这个就是一个Hander
/** * Handle system messages here. */ public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
当callback不为null的时候就调用handleCallback()这个方法,
private static void handleCallback(Message message) { message.callback.run(); }
这方法就直接调用了一个run()方法,看到这里估计小伙伴们会有很多疑问了? 不要急 我们在看看Hander的post的方法
hander.post();
/** * Causes the Runnable r to be added to the message queue. * The runnable will be run on the thread to which this handler is * attached. * * @param r The Runnable that will be executed. * * @return Returns true if the Runnable was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); }
这是一个sendMessage,我们看看getPostMessage(r)
private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }
原来callback就是Runnable,那么前面调用run()也就行的通了; 这就是线程的回调;
接下来我们在看看hander.sendMessage(msg);
public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); }
跟post一样都是调用sendMessageDelayed(msg,0);
这里面第二参数就是该消息多少时间后发送默认是0;
/** * Enqueue a message into the message queue after all pending messages * before (current time + delayMillis). You will receive it in * {@link #handleMessage}, in the thread attached to this handler. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. Note that a * result of true does not mean the message will be processed -- if * the looper is quit before the delivery time of the message * occurs then the message will be dropped. */ public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }/** * Enqueue a message into the message queue after all pending messages * before the absolute time (in milliseconds) <var>uptimeMillis</var>. * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> * Time spent in deep sleep will add an additional delay to execution. * You will receive it in {@link #handleMessage}, in the thread attached * to this handler. * * @param uptimeMillis The absolute time at which the message should be * delivered, using the * {@link android.os.SystemClock#uptimeMillis} time-base. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. Note that a * result of true does not mean the message will be processed -- if * the looper is quit before the delivery time of the message * occurs then the message will be dropped. */ 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); } return queue.enqueueMessage(msg, uptimeMillis); }
注意这个事件
msg.target = this;
这就是我上面为什么会说 msg.target就是一个hander了
在看看这个事件
queue.enqueueMessage
这个方法返回true就是说明消息已经保存到消息队列中了,反之失败;
以上就是hander发送消息的流程了;
总结: 只要是在子线程中使用Hander就先手动创建一个Looper.prepare(),
Hander在new出来的时候就在它的构造方法中通过sThreadLocal.get(),获取当前线程的Looper对象然后Looper有在自己的构造方法中创建MessageQueue消息队列,在调用Looper.loop开启死循环不停的走消息队列中获取消息,剩下就是hander.sendMessage()了;
3 1
- 解析Hander消息处理机制
- Hander消息处理机制的步骤
- Android中的异步消息处理机制Hander
- HTTP 通信, XML 解析, 通过 Hander 实现异步消息处理
- HTTP 通信, XML 解析, 通过 Hander 实现异步消息处理
- 系出名门Android(10) - HTTP 通信, XML 解析, 通过 Hander 实现异步消息处理
- 系出名门Android(10) - HTTP 通信, XML 解析, 通过 Hander 实现异步消息处理
- android HTTP 通信, XML 解析, 通过 Hander 实现异步消息处理 (1)
- android HTTP 通信, XML 解析, 通过 Hander 实现异步消息处理 (1)
- android HTTP 通信, XML 解析, 通过 Hander 实现异步消息处理(2)
- HTTP 通信, 三种方式XML 解析,并通过 Hander 实现异步消息处理
- android HTTP 通信, XML 解析, 通过 Hander 实现异步消息处理
- 系出名门Android(10) - HTTP 通信, XML 解析, 通过 Hander 实现异步消息处理
- 解析windows消息处理机制
- 解析异步消息处理机制
- 解析异步消息处理机制
- 解析异步消息处理机制
- 解析异步消息处理机制
- SSH 远程连接端口转发
- 线程发送时间间隔次数
- linux系统下Mysql5.7安装教程
- Java面试题3
- 本地Wamp环境下帝国备份王安装不了
- 解析Hander消息处理机制
- 从volatile说到i++的线程安全问题
- android.os.FileUriExposedException: file:///sdcard/update/wiiwork.apk exposed beyond app through I
- Ananagrams UVA
- servlet中service() doGet() doPost() 方法
- 查看表空间、表空间文件路径
- 删除oracle无用用户与表空间
- 分布式缓存
- OpenGL 函数 gluLookAt() glScalef() glTranslatef() glRotatef() glFrustum() glPerspective() 的比较