美文网首页
Android线程中一个Looper,多个Handler处理消息

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

作者: Bfmall | 来源:发表于2023-02-21 18:20 被阅读0次

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

    相关文章

      网友评论

          本文标题:Android线程中一个Looper,多个Handler处理消息

          本文链接:https://www.haomeiwen.com/subject/wdhokdtx.html