Handler消息传递详解-主线程到子线程、子线程到主线程、子线程到子线程 (一)

本文深入解析了Android中Handler的消息传递机制,包括Handler、Looper、ThreadLocal的基本原理与使用方法,并通过实例演示了主线程到子线程、子线程到主线程及子线程到子线程的消息传递过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        不知道为什么,写这篇文章的时候,不是无法上传图片,就是无法保存草稿,更郁闷的是,我都写了一小半了。firefox浏览器突然卡死重启,也没保存草稿,恢复后,啥也没了。又要重写。。。。。。。。。。。。

  1. handler消息传递流程
  2. Handler ,Looper ,ThreadLocal 源码详解及解惑
  3. 主线程到子线程、子线程到主线程、子线程到子线程实例演示

1、Handler消息传递流程

           
    Handler不一定非要是子线程向Ui线程传递消息。所以,用Thread1和Thread2来讲:Thread2想给Thread1发送消息。Thread1要做的事情有准备好Looper,准备好Handler, 将Handler传入Thread2, Thread2拿到后,用handler将消息压入消息队列MessageQuene中。Thread1的Looper循环的从MessageQuene中取出消息。交给Handler分发和处理。

2、Handler ,Looper ,ThreadLocal 源码详解及解惑

    2.1 Handler详解
       Handler是个神奇的东西,可以在线程中畅行无阻。你可以在主线程中创建子线程的Handler,也可以在子线程中创建主线程的Handler. 就是这么神奇。怎么创建,可以在后面的实例演示中给大家讲解
 public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
   
    public final boolean sendEmptyMessage(int what)
    {
        return sendEmptyMessageDelayed(what, 0);
    }
   
    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
    }
  
    public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageAtTime(msg, uptimeMillis);
    }

 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);
    }
上面可以看出,Handler的各种发送消息方法。到最后,都是执行了将消息压入消息队列的方法
  private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    } 

这里要注意,msg.target=this; 这里指明了消息的目的地为当前Handler对象,也就是说最后还由Handler来处理的。不行,待会看Looper源码就知道了。

Handler的dispatchMessage和HandlerMessage方法就不讲解了。

    2.2 Looper详解

        习惯了在用handler在线程想主线发消息的同学,对Looper应该比较陌生,认识他估计也是因为将Handle写错地方了,导   致报Looper没有prepare才知道有这个东西。

        那么,为什么在主线程中,不需要理会Looper呢?  那是因为android太贴心了。直接给你在ActivityThread的main()方法里给你初始化好了。去看看就知道了

 public static void main(String[] args) {
        ....................去掉不关心的
      
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

      
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

    可以看到,Looper先执行了prepareMainLooper(),接着执行了Loop()方法。所以,你才不用关心Looper就可以放心使用。那么在其他线程中,想要使用Handler,要不要手动去执行Looper的prepare()和loop()方法呢? 答案是必须的。必须要。

    一起看Looper源码(直接主要的):

public final class Looper {


     /** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}. 这里说了,要在调用方法后调用loop()方法。
      */
    public static void prepare() {
        prepare(true);
    }

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


    /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the 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;

        for (;;) {  //循环取消息
            Message msg = queue.next(); // might block
        //还记得上面说的msg.target么? 看到没?就是它,上面讲到msg.target是handler实例。
                try {
                msg.target.dispatchMessage(msg);
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
           
    }
      

    看到没?loop()方法在preapare()方法说明中,被清楚的说了,要在preapare()调用后调用loop()方法。然后由loop()循环取消息。交给handler去分发。

这里还有一个点值得说下,红色代码部分,一个Thread只有一个Looer,通过这个,可以判断当前线程是否为主线程

方式为:Looper.getMainLooper ==Looper.myLooper

    2.3 ThreadLocal详解

        ThreadLocal 是个更神奇的东西,可以一个实例走遍所有Looper 和线程。啥意思?就是你在主线中,通过ThreadLocal的对象,取出来的Looper是主线程的。用同一个实例对象,在子线程中,调用同一个方法,取出来的是子线程的Looper . 怎么办到的?看上面Looper.prepare()方法的源码 sThreadLocal.set(new Looper(quitAllowed));  在看set方法

  public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
原来是用一个map将thread和looper一一绑定了。

在来解惑一下:为什么Looper在那个线程,Handelr就在那个线程?

Handler其实根本不在乎自己在哪里。主要是Looper在哪个线程里。看看Handler的构造方法:

 public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

    /**
     * Use the provided {@link Looper} instead of the default one and take a callback
     * interface in which to handle messages.  Also set whether the handler
     * should be asynchronous.
     *
     * Handlers are synchronous by default unless this constructor is used to make
     * one that is strictly asynchronous.
     *
     * Asynchronous messages represent interrupts or events that do not require global ordering
     * with respect to synchronous messages.  Asynchronous messages are not subject to
     * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
     *
     * @param looper The looper, must not be null.
     * @param callback The callback interface in which to handle messages, or null.
     * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
     * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
     *
     * @hide
     */
    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

可以看到,如果没有指定Looper,那么Looper就是当前线程的Looper,如果指定了Looper,那就不一定是当前线程的Looper了。那么这个时候Handler所在线程就得随着Looper而改变了。下面在实例演示中可以看看。

Handler消息传递详解-主线程到子线程、子线程到主线程、子线程到子线程 (二)

源码示例下载:https://download.youkuaiyun.com/download/shoneworn/10437255


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值