Android线程中一个Looper,多个Handler处理消息

2023-02-21  本文已影响0人  Bfmall

问题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<Looper> sThreadLocal = new ThreadLocal<Looper>();
 
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");
    }

Looper.prepareMainLooper()方法:

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

————————————————
版权声明:本文为CSDN博主「lidongxiu0714」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u010126792/article/details/82899976

上一篇下一篇

猜你喜欢

热点阅读