Handler学习笔记和面试记录

以下内容是自己面试和学习的记录,欢迎吐槽

handler组成部分

Handler

handler就是用来发送消息和处理消息的,发送消息我们一般使用的都是Send和Post方法这个系列的方法,而这个Post一系列方法是通过Send一系列方法来实现的,而send的这些方法最后都是通过SendMessageAtTime()方法来实现的,Handler发送一条消息,就在消息队列中插一条消息。除了sendMessageAtFrontOfQueue()这个方法 会直接调用enqueueMessage

public final boolean post(Runnable r)
{
   return  sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean sendMessage(Message msg)
{
    return sendMessageDelayed(msg, 0);
}
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;
    }
    return enqueueMessage(queue, msg, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
    Message msg = Message.obtain();
    msg.what = what;
    return sendMessageDelayed(msg, 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);
}

最后

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}
会调用MessageQueue.enqueueMessage 这是核心代码 msg.target=this,也是一个面试题的点

Message

Message是在线程之间传递的消息,它可以在内部携带少量的数据,用于线程之间交换数据。Message有四个常用的字段,what字段,arg1字段,arg2字段,obj字段。what,arg1,arg2可以携带整型数据,obj可以携带object对象。注意Message里面的Handler traget 字段后面一个面试题会用到

MessageQueue

MessageQueue是消息队列的意思,它主要用于存放所有通过Handler发送的消息,这部分的消息会一直存在于消息队列中,等待被处理。每个线程中只会有一个MessageQueue对象。

Looper

每个线程通过Handler发送的消息都保存在,MessageQueue中,Looper通过调用loop()的方法,就会进入到一个无限循环当中,然后每当发现Message Queue中存在一条消息,就会将它取出,并传递到Handler的handleMessage()方法中。每个线程中只会有一个Looper对象。

  • 在主线程中,Activity会默认为我们开启Looper,无需我们手动调用Looper.prepare

在ActivityThread.class里面

在Looper.class里面

  • 子线程必须调用Looper.prepare()和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;

  ......省略

    boolean slowDeliveryDetected = false;
    //可以看到Looper会一便利MQ
    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;
        long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
        long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
        if (thresholdOverride > 0) {
            slowDispatchThresholdMs = thresholdOverride;
            slowDeliveryThresholdMs = thresholdOverride;
        }
        final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
        final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);

        final boolean needStartTime = logSlowDelivery || logSlowDispatch;
        final boolean needEndTime = logSlowDispatch;

        if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
            Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
        }

        final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
        final long dispatchEnd;
        try {
        //分发给对应的handler
            msg.target.dispatchMessage(msg);
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
       .....省略
        msg.recycleUnchecked();
    }
}

ThreadLocal

MessageQueue对象,和Looper对象在每个线程中都只会有一个对象,怎么能保证它只有一个对象,就通过ThreadLocal来保存。Thread Local是一个线程内部的数据存储类,通过它可以在指定线程中存储数据,数据存储以后,只有在指定线程中可以获取到存储到数据,对于其他线程来说则无法获取到数据。

面试题:

问题1:一个线程中初始化多个handler,会产生多少个looper?

问题2:如果只有一个looper,looper如何区分handler,handler发送了消息会不会导致Looper错乱,最终不知道谁处理。

1 一个线程中初始化多个handler,会产生多少个looper
分析一下:做过android开发的都知道Handler是android的消息机制,在主线程可以直接使用handler,那是因为主线程已经默认帮我们初始化了Looper,调用了Looper.prepare()和loop(),我们可以在主线程定义多个handler都不用自己生成或绑定Looper,所以一个线程只有一个Looper,可能大家会信这个分析,来看看Looper源码:

线程只有一个Looper:
 

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
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));
}

可以明确看出,如果存在Looper就会报错,一个线程产生一个looper

2 一个looper,多个Handler,handler发送的消息利用dispatchMessage处理时如何区分
打开Message源码可以发现,Handler发送消息的时候

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

Handler会被付给Message.target一起添加到稍息队列

Looper.loop()方法会循环拿到

msg.target.dispatchMessage(msg);

调用对应handler的dispatchMessage方法

 


以上文档参考原文链接:https://blog.csdn.net/qq_38308277/article/details/79667540

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值