Handler机制理解二

本文基于Android API 24 Platform 中 android.jar下的os中的代码;

在Actiivity启动的时候会启动一个ActivityThread线程,在这里面会执行Looper.prepareMainLooper();方法创建一个looper,其中Looper类很干净,没有继承任何父类,也没有实现任何接口。看一下prepareMainLooper()的源码:

public static void prepareMainLooper() {
        prepare(false); //将looper放入一个线程池中
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
          //从线程池中拿到looper并赋值给sMainLooper
            sMainLooper = myLooper();
        }
    }

public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

看一下prepare(boolean quitAllowed)的代码:

//参数表示是否允许退出,Activity的MainLooper是false,一般我们Looper.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));//放入线程池中,因为这个线程池是一个map,所以用set方法
}

你知道new Looper(quiteAllowed)都执行了什么方法吗?

private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);//这样就获得了MessageQueue的引用
        mThread = Thread.currentThread();
    }

在Looper.prepareMainLooper();之后会执行Looper.loop()方法,看看源码吧:

public static void loop() {
  //myLooper()方法获取looper
   final Looper me = myLooper();
   if (me == null) {
   throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
   }
    //获取looper所关联的MessageQueue
    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死循环遍历MessageQueue中的Message,其实是Message.next获取下一个Message
        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 {
              //分发Message,target其实是Handler,会调用Handler的dispatchMessage方法,其中会
              //调用callBack的handleMessage(msg)
                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.
            //确保在调度过程中,线程的标识没有被破坏
            //在for循环之前也调用了这个方法,两个比较,确定没有变
            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();
        }
    }

到这里为止,你的messageQueue、Looper都已经创建好了,looper也开启了循环,这些都是Activity给你写好的;这时你就在Activity中写了一个new Handler(){ … };其中会重写handleMessage函数,你会想,我的这个Handler是如何与Looper和MessageQueue联系起来的?看看new Handler的时候你都做了什么?

public Handler() {
  //会调用2个参数的方法
    this(null, false);
}

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());
            }
        }
        //从线程池中拿到Looper
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        //拿到messageQueue
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

很简单吧,这时你发送了一个Message,如sendMessage:

public final boolean sendMessage(Message msg) {
        return sendMessageDelayed(msg, 0); //调用2个参数的sendMessageDelayed()方法
}

这里说一下:不管你是sendMessage()、sendMessageDelayed()、sendEmptyMessage()、sendEmptyMessageDelayed()、post()、postDelayed()最后都会走到sendMessageDelayed()方法;

public final boolean sendMessageDelayed(Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
 return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);//调用sendMessageAtTime
}

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;//拿到MessageQueue
        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将message放进MessageQueue
}

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this; //把Handler给msg的target,所以说target就是handler
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);//调用Queue的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;  //将延迟时间赋值给msg.when属性,以后从MessageQueue中拿消息时(next()方法),会判断这个时间,做到延迟发送。
            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;
              //死循环,直到p为链表最后一个
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                //将message放入最后一个
                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循环是发现了新的Message就会调用message的target的dispatchMessage()方法 ,也就是发送给Handler的handlerMessage方法。

问题:

Looper是怎么轮询消息的?

答:for死循环,之后调用msg.target.dispatchMessage(msg);

Message是怎么做到延迟发送的?
答:在enqueueMessage()中有一句msg.when = when;将时间放入msg中,然后再放入MessageQueue中;Looper循环的时候有一句 Message msg = queue.next(); MessageQueue的next()方法如下:

......//省略部分代码
for(; ;){
......//省略部分代码
final long now = SystemClock.uptimeMillis();
......//省略部分代码
 if (now < msg.when) {
       // 在这里判断有延时要求时做操作
       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 (DEBUG) Log.v(TAG, "Returning message: " + msg);
             msg.markInUse();
             return msg;
         }
   }

最外层是有一个死循环,随着now的增加,到了now >= msg.when的时候就会之取出这个message。
Looper为什么没有造成线程阻塞?

答:这个问题,网上有好多答案,从不同角度,我总结一下:ActivityThread执行过程中就执行了Looper的创建和looper(),根据ActivityThread代码,整个Activity的生命周期都是跑在looper循环里的,ActivityThread也处理了各种Handler的情况,所以Actiivty中的任何操作都不会造成阻塞。从进程角度讲,Looper就应该阻塞,否则应用程序就自己退出了,我们需要保证其不会自己退出,可以让用户一直使用,所以for循环是死循环。从Linux的角度讲,没有阻塞一说,Looper只是一直在循环消息,没有消息就沉睡,有消息时就被唤醒,执行Activity中的方法,知道退出。阻塞和我们认为的ANR不同,Looper是循环消息并拿出,并没有耗时操作,不会阻塞。

Message内部长什么样子?

答:Message就是链表的结点,除了有what、arg1、arg2、obj等属性外符合链表特点。

MessageQueue是怎么保存Message的?

答:链表。与其说是保存不如说是对Message的操作类,也许我的理解有误,现阶段我是这么理解的。

new Message()和obtainMessage()的区别?

答:obtainMessage是从Message池中拿出Message,没有的话才会new Message();看代码,最后都会调用Message的obtain()方法:

public static Message obtain() {
    synchronized (sPoolSync) {
        if (sPool != null) {
            Message m = sPool;
            sPool = m.next;
            m.next = null;
            m.flags = 0; // clear in-use flag
            sPoolSize--;
            return m;
          }
       }
    return new Message(); //最后才会new个对象
}

常见知识点:

主线程的looper在Activity创创建时系统帮我们创建好了,但是我们自己开启的子线程需要自己去开启Looper.prepare()和Looper.looper();

如有错误,欢迎指正;

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值