Handler我们经常用,一般是用在子线程给主线程发消息,通知主线程做更新UI的操作,但是现在假如说,让你在主线程给子线程发消息呢?
public class MainActivity extends Activity {
private MyLinearLayout mParent;
private Handler subHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
Button button = findViewById(R.id.my_button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
subHandler.sendEmptyMessage(0);
}
});
}
private void init() {
new Thread("子线程哈哈") {
@Override
public void run() {
//创建looper对象,并与当前线程绑定
Looper.prepare();
subHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Toast.makeText(MainActivity.this, "当前线程:" + Thread.currentThread()
.getName() , Toast.LENGTH_SHORT).show();
return true;
}
});
//轮询Looper里面的消息队列
Looper.loop();
}
}.start();
}
上面就是使用Handler在主线程给子线程发消息的demo,点击按钮后,主线程发消息给子线程,子线程收到消息后,Toast的结果是:当前线程:子线程哈哈.
但是如果我把Looper.prepare();
去掉,就会报错:java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
对比在主线程创建handler,在子线程给主线程发消息的使用方式,唯一的区别就是加了2行代码:
Looper.prepare();
........
Looper.loop();
那为什么,在主线程中创建handler,我们直接new就可以,但是在子线程不行呢?Hanlder的工作原理是什么?源码是最好的老师,所以下面学习一下Handler的源码
学习Handler的源码之前,首先回顾一下一般情况下Handler的基本使用步骤:
1, 在主线程直接创建一个Handler对象,重写或实现
handlerMessage()
,在handlerMessage()
里面写收到消息后的处理逻辑
2, 在子线程中需要通知主线程的地方,调用handler.sendMessage()
只有2步,使用起来很简单. 我们就顺着这个使用步骤去看Handler的源码,看它到底怎么工作的,怎么就能够让2个不同的线程之间能够通信
Handler的构造方法:
public Handler() {
this(null, false);
}
public Handler(Callback callback) {
this(callback, false);
}
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
public Handler(boolean async) {
this(null, async);
}
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());
}
}
//从当前线程的ThreadLocalMap里面查找有没有对应的looper
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue; //将looper的Queue赋值handler的成员mQueue
mCallback = callback;
mAsynchronous = async;
}
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
Looper.myLooper()
Handler有7个重载的构造方法,我们直接看倒数第二种构造方式,可以看到调用了mLooper = Looper.myLooper();
:
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
sThreadLocal
是Looper
类的一个静态成员,它是一个ThreadLocal
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
所以通过上面的代码可以看到,Looper.myLooper()
就是取出当前线程的ThreadLocalMap里面存储的key为Looper
的静态成员sThreadLocal
所对应的looper对象.(有关ThreadLoca知识,请前往深入理解 Java 之 ThreadLocal 工作原理)
如果当前线程(Handler在哪个线程创建就代表哪个线程)的ThreadLocalMap里面没有Looper
对象,就会报错提示:不能在没有调用Looper.prepare()
的线程里创建Handler对象,如果有Looper
,就将Looper
的mQueue
赋值给Handler
的成员mQueue
Looper.prepare()
前面提到,如果要创建Handler对象,必须要有Looper,如果没有Looper,会报错提示要调用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));
}
先从当前线程的ThreadLocalMap
里面去取出key为Looper
类的静态成员sThreadLocal
对应的looper对象,如果已经有looper,就报错:每一个线程只能有一个looper对象. 如果没有looper,就新建一个,并存入当前线程的ThreadLocalMap
,存入的key是Looper
类的sThreadLocal
. 看到这里,我们可能会想平时我们用的时候并没有去调用Looper.prepare()
,其实是系统已经帮我们做了:
//ActivityThread#main()
public static void main(String[] args) {
........
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
在应用程序的入口ActivityThread
的main()
方法里面(ActivityThread不是一个线程,只是一个普通类),调用 了Looper.prepareMainLooper();
public static void prepareMainLooper() {
//新建一个looper对象,并存进ThreadLocalMap
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
//给主线程对应的looper赋值
sMainLooper = myLooper();
}
}
Looper也有一个获取主线程对应的looper的方法getMainLooper()
:
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
再看一下Looper
的构造方法:
private Looper(boolean quitAllowed) {
//Looper对象创建的时候,会创建一个 MessageQueue
mQueue = new MessageQueue(quitAllowed);
//Looper对应的线程
mThread = Thread.currentThread();
}
Handler初始化过程总结
从前面Handler的创建过程源码可以得出:
1,创建Handler对象之前,必须要先创建Looper,Looper与线程对应,一个线程只能有一个Looper
2,创建Handler对象之前,会先检查Handler对象创建时所在的线程是否已经有一个对应的Looper,检查是通过调用Looper.myLooper()
方法,内部原理是通过每个线程内部的ThreadLocalMap
查找key为Looper
的静态成员ThreadLocal
对应的Looper对象是否为null
3,如果Handler对象创建时所在的线程没有对应的Looper,那么会抛异常,在主线程创建除外。所以在主线程以外的线程创建Handler之前要先调用Looper.prepare()
创建一个Looper,该方法内部同时会把Looper
的静态成员ThreadLocal
作为key,把Looper对象做为value值,存进Handler对象创建时所在的线程的ThreadLocalMap
,Looper就与当前线程对应了
4,Looper对象创建的时候,会创建一个MessageQueue
,该MessageQueue
会在构造Handler对象的时候,赋值给Handler的成员mQueue
,Looper对象本身也会赋值给Handler的成员mLooper
消息的发送
有了Handler对象后,就可以发送消息了,看一下Handler发送消息的方法:
public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg, 0);
}
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageAtTime(msg, uptimeMillis);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
//第二个参数传递的是从系统开机到当前时间的毫秒数+延迟时间
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
//第二个参数uptimeMillis表示消息发送的时间
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
//Handler的成员mQueue就是构造Handler对象时,Looper里面的MessageQueue
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);
}
public final boolean sendMessageAtFrontOfQueue(Message msg) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
//发送消息到消息队列的头部,因为第三个参数传的是0
return enqueueMessage(queue, msg, 0);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//把Handler赋值给Message的target,后面从消息队列取出消息后就是交给这个target(Handler)处理
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
上面那么多发送消息的方法,除了sendMessageAtFrontOfQueue()
以外,其余都是调用sendMessageAtTime()
,这两个方法其实也是一样的,sendMessageAtTime()
的第二个参数传0这两个方法就是一样了。但是这两个方法最终都调用了enqueueMessage()
,而enqueueMessage()
又调用了MessageQueue
的enqueueMessage()
,也就是把消息插入到消息队列
消息入队
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(TAG, 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) {
//p为null(代表MessageQueue没有消息) 或者消息的发送时间是队列中最早的
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;
//将消息按时间顺序插入到MessageQueue
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.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
Looper.loop();
消息插入到消息队列了,肯定要取出来才能用,从消息队列取消息的方法就是开头demo中的Looper.loop();
public static void loop() {
//取出当前线程对应的looper
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//取出looper里面的消息队列
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(); // 从消息队列取出消息,会阻塞
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
.......
try {
//分发消息,把消息交给msg.target也就是Handler处理
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
........
msg.recycleUnchecked(); //将不再使用的消息放入消息池
}
}
消息出队
取消息的时候,调用了消息队列的消息出队方法next()
//MessageQueue #next()
Message next() {
final long ptr = mPtr;
if (ptr == 0) { //当消息循环已经退出,则直接返回
return null;
}
int pendingIdleHandlerCount = -1; // 循环迭代的首次为-1
int 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) {
//如果消息没有 target,那它就是一个屏障,需要一直往后遍历找到第一个异步的消息
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) { //如果这个消息还没到处理时间,就设置个时间过段时间再处理
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 正常消息的处理
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next; //取出当前消息,链表头结点后移一位
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
//没有消息
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
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);
}
// 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 handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
pendingIdleHandlerCount = 0;
nextPollTimeoutMillis = 0;
}
}
Handler.dispatchMessage()
Looper.loop()
里面从消息取出消息后,调用了msg.target.dispatchMessage(msg);
public void dispatchMessage(Message msg) {
if (msg.callback != null) { //
handleCallback(msg);
} else {
if (mCallback != null) { //构造Handler的时候传入的Callback
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg); //构造Handler时候,Callback如果传null,就走这里,它是空实现
}
}
一般情况下,我们使用Handler都是使用 Handler handler=new Handler()
这种构造方式,通过前面Handler的构造方法源码可以知道,这种构造方式的mCallback
传的是null(不是Message的callback),所以当handler取出消息要处理的时候,会回调handleMessage(msg);
而它是空实现,所以我们需要覆写handleMessage()
那么什么时候会调用if条件语句里面的handleCallback(msg)
呢,其实Handler不仅只有sendMessageXXX
发送消息方法,还有postXXX
发送消息的方法
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean postAtTime(Runnable r, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}
public final boolean postDelayed(Runnable r, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
public final boolean postAtFrontOfQueue(Runnable r)
{
return sendMessageAtFrontOfQueue(getPostMessage(r));
}
有5个postXXX
发送消息的方法,但还是调用了sendXXX
方法,只是传递参数的过程中调用了一个getPostMessage()
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
看到这里就明白了,只有调用postXXX
发送消息的方法,才会走Handler.dispatchMessage()
的if语句里面的回调,其实我们常用更新UI的方式:Activity.runOnUiThread(Runnable)
, View.post(Runnable)
;和View.postDelayed(Runnable action, long delayMillis)
都是调用Handler的post方法发送消息
//Activity#runOnUiThread
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action); //这个Handler是Activity的成员变量
} else {
action.run();
}
}
//View#post
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
// Postpone the runnable until we know on which thread it needs to run.
// Assume that the runnable will be successfully placed after attach.
getRunQueue().post(action);
return true;
}
关于Message的其他知识
1,
Message
的成员what
表示的是消息的类型(用于标识干什么用的)
2,获取一个Message
对象最好的方式不是直接new,而是使用Message.obtain()
,或者Handler.obtainMessage()
这种方式会复用消息池中的消息,而不是新建
最后再总结一下Handler机制:
1,每一个Handler创建的时候必须要有一个Looper(要么传入,要么通过当前线程获取),每一个Looper对应一个线程和MessageQueue,一个线程可以创建多个Handler,但只能创建一个Looper
2,如果Handler创建时所在的线程和Looper创建时所在的线程是同一个线程,Handler对象创建的时候会通过当前线程的ThreadLocal的内部类ThreadLocalMap检查当前线程是否已经有一个Looper,如果是在主线程创建的Handler,Looper的创建和轮询消息队列的操作,主线程已经在ActivityThread已经帮我们做了,如果不是在主线程创建的Handler,需要我们自己手动调用Looper.prepare()来创建Looper和调用Looper.loop()轮询消息队列,如果我们不手动调用,会报错!特别注意:Handler的创建线程可以和Looper的创建线程不是同一个线程
3,Handler对象创建的时候,会把Looper持有的MessageQueue赋值给Handler的MessageQueue,同时也会把Looper赋值给Handler的Looper,Handler发消息其实是把消息发送到Looper的MessageQueue,也就是说Handler持有的Looper在哪个线程创建的(Looper.prepare()
和Looper.loop()
一般都会在一个线程),消息也就发给哪个线程
4,发送消息的过程中,Handler会把自身设置为当前消息的Target(Handler.enqueueMessage()
里面设置),这样即使在一个线程创建了多个Handler,接收的Handler就永远是那个发送的Handler,而不会是别的Handler,别且这多个Handler共用一个Looper和MessageQueue