一个线程多个handler会有多少个looper,looper如何区分handler,会不会导致消息错乱。

面试题:

问题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:

 // sThreadLocal.get() will return null unless you've called prepare().
    static final ThreadLocal sThreadLocal = new ThreadLocal();

public static void prepare() {
        prepare(true);
    }


    //如果不为null,会报异常,所以一个线程只能调用一次prepare,生成一个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:

这里的主线程就是UI线程,Activity由ActivityThread启动,会调用ActivityThread的main函数:

//ActivityThread.java 
public static void main(String[] args) {
       //调用了Looper的prepareMainLooper

        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"));
        }

        //调用了loop,开始循环
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
 public static void prepareMainLooper() {
        prepare(false);//初始化looper,放入sThreadLocal
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

 //返回和当前线程关联的Looper
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

对于Looper.loop()后面会进行分析

2 一个looper,多个Handler,handler发送的消息利用dispatchMessage处理时如何区分

首先说明,一个handler发送的消息只会被自己接收,所以是可以正常处理的(就不demo演示了)

发送消息除了利用Handler之外还有Message,Message一般利用Obtain获取,其实obtain中还可以传递参数,可以接收Message,还可以接收Handler,message有多个属性,常用的有what,arg1,arg2,data等,其实还有一个属性叫做target,这个target属性就是标识handler的。

handler发送message一般调用sendMessage:

Handler.java

public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }

public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return 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,

 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//会把this赋值给msg.target,此时target就指向当前Handler
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
//之后调用MessageQueue的enqueueMessage分发消息进行处理
        return queue.enqueueMessage(msg, uptimeMillis);
    }

最终是Looper取Messagequeue中的消息,交给Handler处理:

Looper.java

 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;

        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 slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;

            final long traceTag = me.mTraceTag;
            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
            final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            final long end;
            try {

    //这里可以很明显的看到调用message.target.dispatchMessage
                msg.target.dispatchMessage(msg);
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            if (slowDispatchThresholdMs > 0) {
                final long time = end - start;
                if (time > slowDispatchThresholdMs) {
                    Slog.w(TAG, "Dispatch took " + time + "ms on "
                            + Thread.currentThread().getName() + ", h=" +
                            msg.target + " cb=" + msg.callback + " msg=" + msg.what);
                }
            }

            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();
        }
    }

分析完毕!

你可能感兴趣的:(android基础,java面试小问题)