1、handler在主线程和子线程互相通信(子线程和子线程的通信)简单使用
我们使用handler,可以实现主线程和子线程之间的相互通信,然后子线程和子线程之间的通信,如果不清楚,基本用法请先参考我的这篇博客
Android之用Handler实现主线程和子线程互相通信以及子线程和子线程之间的通信 http://blog.csdn.net/u011068702/article/details/75577005
2、handler在主线程为什么不需要调用Looper.prepare()
我们看下Looper.java这个类,它在安卓android.os包下,我们看这个类的一开始的注释
* <p>This is a typical example of the implementation of a Looper thread,* using the separation of {@link #prepare} and {@link #loop} to create an* initial Handler to communicate with the Looper.** <pre>* class LooperThread extends Thread {* public Handler mHandler;** public void run() {* Looper.prepare();** mHandler = new Handler() {* public void handleMessage(Message msg) {* // process incoming messages here* }* };** Looper.loop();* }* }</pre>
很明显,在一个线程里面需要使用Handler之前需要Looper.prepare(),但是我们平时在主线程更新UI的时候,为什么没有看到这行代码呢?
我们看下ActivityThread.java这个类,它在安卓包名android.app目录下,我们知道ActivityThread.java这个类是安卓程序的入口,我们看下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);Environment.initForCurrentUser();// Set the reporter for event logging in libcoreEventLogger.setReporter(new EventLoggingReporter());Security.addProvider(new AndroidKeyStoreProvider());// Make sure TrustedCertificateStore looks in the right place for CA certificatesfinal File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());TrustedCertificateStore.setDefaultUserDirectory(configDir);Process.setArgV0("<pre-initialized>");Looper.prepareMainLooper();ActivityThread thread = new ActivityThread();thread.attach(false);if (sMainThreadHandler == null) {sMainThreadHandler = thread.getHandler();}if (false) {Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG, "ActivityThread"));}Looper.loop();throw new RuntimeException("Main thread loop unexpectedly exited");}
我们可以看到有Looper.prepareMainLooper()函数,我们点击进去
public static void prepareMainLooper() {prepare(false);synchronized (Looper.class) {if (sMainLooper != null) {throw new IllegalStateException("The main Looper has already been prepared.");}sMainLooper = myLooper();}}
然后看到了prepare(false)函数,我们再点击这个函数
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));}
我们可以看到这里就调用prepare函数,所以主线程不需要调用Looper.prepare()函数,然后我们也可以看到这里有行这个代码
if (sThreadLocal.get() != null) {throw new RuntimeException("Only one Looper may be created per thread");}
在Looper.java类中,我们的Looper保存在ThreadLocal里面
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
用ThreadLocal修饰的变量,可以理解为只有当前线程可以改变这个参数,其它线程不可以改变这个参数,如果你对ThreadLocal不清楚,单独可以先看下我这篇博客的简单使用
java之ThreadLocal简单使用总结 http://blog.csdn.net/u011068702/article/details/75770226
if (sThreadLocal.get() != null) {throw new RuntimeException("Only one Looper may be created per thread");}
上面的代码写得很清楚了,如果当前的sThreadLocal对象里面有个Looper对象,那么就会抛出异常,而且英文也提示了,所以,一个线程为什么只能有一个Looper对象的原因,所以如果在程序里面,每个线程调用2次Looper.prepare()就会报错,我们再看这行代码
sThreadLocal.set(new Looper(quitAllowed));
点击Looper的构造函数
private Looper(boolean quitAllowed) {mQueue = new MessageQueue(quitAllowed);mThread = Thread.currentThread();}
里面构建了一个MessageQueue对象,上面我们分析一个线程只有一个Looper对象,那么Looper对象只构建一个,也就意味着MessageQueue对象也只构建一次,所以一个线程也只有一个MessageQueue对象的原因。
在main函数里面,也调用了Looper.loop()函数,后面分析这个方法
3、分析Handler发送消息
我们先看下Handler.java的构造方法,这个类在安卓 android.os这个目录下面
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;}
这里看出初始化变量,然后保存了当前线程中的Looper对象。
发送消息的时候我们一般都这样写
handler.sendMessage(message)
所以我们点击 sendMessage方法看下
public final boolean sendMessage(Message msg){return sendMessageDelayed(msg, 0);}
再点击sendMessageDelayed(msg, 0);
public final boolean sendMessageDelayed(Message msg, long delayMillis){if (delayMillis < 0) {delayMillis = 0;}return sendMessageAtTime(msg, SystemClock.uptimeMillis() + 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);}
再点击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就是Handler对象本身,再点击queue.enqueueMessage(msg, uptimeMillis)(在MessageQueue这个类里面)
boolean enqueueMessage(Message msg, long when) {if (msg.target == null) {throw new IllegalArgumentException("Message must have a target.");}if (msg.isInUse()) {throw new IllegalStateException(msg + " This message is already in use.");}synchronized (this) {if (mQuitting) {IllegalStateException e = new IllegalStateException(msg.target + " sending message to a Handler on a dead thread");Log.w("MessageQueue", e.getMessage(), e);msg.recycle();return false;}msg.markInUse();msg.when = when;Message p = mMessages;boolean needWake;if (p == null || when == 0 || when < p.when) {// New head, wake up the event queue if blocked.msg.next = p;mMessages = msg;needWake = mBlocked;} else {// Inserted within the middle of the queue. Usually we don't have to wake// up the event queue unless there is a barrier at the head of the queue// and the message is the earliest asynchronous message in the queue.needWake = mBlocked && p.target == null && msg.isAsynchronous();Message prev;for (;;) {prev = p;p = p.next;if (p == null || when < p.when) {break;}if (needWake && p.isAsynchronous()) {needWake = false;}}msg.next = p; // invariant: p == prev.nextprev.next = msg;}// We can assume mPtr != 0 because mQuitting is false.if (needWake) {nativeWake(mPtr);}}return true;}
可以看出MessageQueue从而按照时间将所有的Message排序
然后我们不是最后还调用了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 blockif (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 loggerPrinter 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.recycleUnchecked();}}
Looper.loop()方法里起了一个死循环,不断的判断MessageQueue中的消息是否为空,如果为空则直接return掉,然后执行queue.next()方法,点击进去
Message next() {// Return here if the message loop has already quit and been disposed.// This can happen if the application tries to restart a looper after quit// which is not supported.final long ptr = mPtr;if (ptr == 0) {return null;}int pendingIdleHandlerCount = -1; // -1 only during first iterationint nextPollTimeoutMillis = 0;for (;;) {if (nextPollTimeoutMillis != 0) {Binder.flushPendingCommands();}nativePollOnce(ptr, nextPollTimeoutMillis);synchronized (this) {// Try to retrieve the next message. Return if found.final long now = SystemClock.uptimeMillis();Message prevMsg = null;Message msg = mMessages;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());}if (msg != null) {if (now < msg.when) {// Next message is not ready. Set a timeout to wake up when it is ready.nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);} else {// Got a message.mBlocked = false;if (prevMsg != null) {prevMsg.next = msg.next;} else {mMessages = msg.next;}msg.next = null;if (false) Log.v("MessageQueue", "Returning message: " + msg);return msg;}} else {// No more messages.nextPollTimeoutMillis = -1;}// Process the quit message now that all pending messages have been handled.if (mQuitting) {dispose();return null;}// If first time idle, then get the number of idlers to run.// Idle handles only run if the queue is empty or if the first message// in the queue (possibly a barrier) is due to be handled in the future.if (pendingIdleHandlerCount < 0&& (mMessages == null || now < mMessages.when)) {pendingIdleHandlerCount = mIdleHandlers.size();}if (pendingIdleHandlerCount <= 0) {// No idle handlers to run. Loop and wait some more.mBlocked = true;continue;}if (mPendingIdleHandlers == null) {mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];}mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);}// Run the idle handlers.// We only ever reach this code block during the first iteration.for (int i = 0; i < pendingIdleHandlerCount; i++) {final IdleHandler idler = mPendingIdleHandlers[i];mPendingIdleHandlers[i] = null; // release the reference to the handlerboolean keep = false;try {keep = idler.queueIdle();} catch (Throwable t) {Log.wtf("MessageQueue", "IdleHandler threw exception", t);}if (!keep) {synchronized (this) {mIdleHandlers.remove(idler);}}}// Reset the idle handler count to 0 so we do not run them again.pendingIdleHandlerCount = 0;// While calling an idle handler, a new message could have been delivered// so go back and look again for a pending message without waiting.nextPollTimeoutMillis = 0;}}
Message的出栈操作,里面可能对线程,并发控制做了一些限制等。获取到栈顶的Message对象,然后就执行这个函数
msg.target.dispatchMessage(msg);
我么知道msg.tartget对象就是handler对象,我们点击dispatchMessage(msg)函数
/*** 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);}}
我们可以知道msg.callback != null的时候,就执行了handleCallback(msg)
private static void handleCallback(Message message) {message.callback.run();}
意味着这个Runable执行 run方法
然后还有就是也可能会执行到这里来
handleMessage(msg);
点击进去,
/*** Subclasses must implement this to receive messages.*/public void handleMessage(Message msg) {}
我们一般在主线程这样写接收消息
public Handler mHandlerCToP = new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch(msg.what) {case 0:break;default:break;}}};
也就意味着把handleMessage()方法重写了,所以我们的代码,有地方发送消息,loop()不断分发消息,当收到了,如果接收到了,我们重写handleMessage就会掉到这个地方来,得到我需要的数据。
4、分析runOnUiThread方法和Handler.post方法和view的post方法
1、分析runOnUiThread()方法
我们一般在子线程调用这个方法也可以来更新UI
runOnUiThread(new Runnable() {@Overridepublic void run() {}});
点击进去
public final void runOnUiThread(Runnable action) {if (Thread.currentThread() != mUiThread) {mHandler.post(action);} else {action.run();}}
再点击mHandler.post(action) 方法
public final boolean post(Runnable r){return sendMessageDelayed(getPostMessage(r), 0);}
点击进去
private static Message getPostMessage(Runnable r) {Message m = Message.obtain();m.callback = r;return m;}
看到了吗?其实最后还是到了发送消息这里,一开始我们不是分析了Looper.loop()里面的dispatchMessage()方法吗?
我么知道msg.tartget对象就是handler对象,我们点击dispatchMessage(msg)函数/*** 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);}}
很明显程序,会走handleCallback(msg);所以会调到handler.java里面的这个方法
private static void handleCallback(Message message) {message.callback.run();}
这样就执行了这个Runnable
2、分析handler.post()方法
上面那个函数内部有handler.post()这个方法,已分析
3、分析view.post()方法
点击view.post()方法
public boolean post(Runnable action) {final AttachInfo attachInfo = mAttachInfo;if (attachInfo != null) {return attachInfo.mHandler.post(action);}// Assume that post will succeed laterViewRootImpl.getRunQueue().post(action);return true;}
可以发现其调用的就是activity中默认保存的handler对象的post方法