Looper, Handler, Message, Thread

在子线程中创建能否创建多个 Handler ,是否会存在多个 Looper?

可以创建多个 Handler ,但不会存在多个 Looper ,在调用

    Handler handler;
    new Thread(){

        public void run(){
            Looper.prepare();//实例一个 Looper 加入 ThreadLocal
            handler = new Handler();//字线程中创建,可多个    
            //do something
            handler.post(new Runnable(){...});//产生消息,加入队列
            Looper.loop();//消息循环
        }

    }.start();

后只会在该线程中创建一个 Looper 实例,并保存在 ThreadLocal<> 中,多次调用会 Looper.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));
    }

在该线程中所创建的 Handler 中,所产生的消息 Message 均会加到该线程的 Looper 中的消息队列 Queue 中,所不同的是不同 Handler 所产生的 Message 在它对应的 Handler 的 handlerMessage() 或 callback 中进行处理,故不管创建 Handler 数量多少,均不会对线程或 Looper 产生影响。

    //handler 中把 Message 加入队列
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

    //Queue 队列,消息加入队列
    boolean enqueueMessage(Message msg, long when) {
        ...//省略
    }

Looper 消息循环

  • Looper 为静态类,在 APP 启动后实例化 sMainLooper 即主线程 Looper ,可用 Looper.getMainLooper() 与 Looper.myLooper() 进行比较判断当前线程是否为主线程( ui 线程)
  • Looper 中有 ThreadLocal <Looper> 用于存放其他线程所产生的 Looper ,保障子线程的消息通信
  • Queue 消息队列,用于存放 Handler 产生的 Message ,并在 loop() 循环取出将消息发出,在子线程中,当队列中消息为空时退出循环

可以理解为, Looper 是一个消息容器,接收消息、存放消息、发送消息

Handler 消息产生以及消息处理

  • 创建 Handler 可以为空方法,默认线程为当前线程,将产生的消息添加到当前线程的 Looper.queue 中,如果 Looper 不存在将报错
  • 处理消息( Message ),在构造方法 handleMessage 中处理,或者定义的 callback 中对消息进行处理
  • 消息派发调用 dispatchMessage

Message 消息个体

  • 包含 what,arg,obj,target 等基本参数
  • 加入队列后,消息派送实际回调 target ,如 handler 的 handleMessage, runnable 的 run 方法。

Looper 消息循环派发

    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;
            }
            //消息处理,回调 target 处理(handleMessage/callback)
            try {
                msg.target.dispatchMessage(msg);
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            ...//省略
            msg.recycleUnchecked();//回收
        }
    }

猜你喜欢

转载自blog.csdn.net/ganfanzhou/article/details/79764882