【Android】Handler是如何切换线程的?

1、问题:handler是如何切换线程的?

想要了解这个问题,需要知道Handler、Message、MessageQuene、Looper之间的关系:

首先Message由Handler生成并放入MessageQuene中,Looper持有MessageQuene并不停的尝试从中取出Message交由Handler处理。

2、我们从代码角度看一下一个主线程发出的Message在子线程被执行的流程:

2.1 首先在创建一个HandlerThread线程,它的特点是run方法生成一个Looper

  thread = new HandlerThread("handler_thread#");
  thread.start();

看一下HandlerThread#run都执行了什么操作:


    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

首先生成了一个Looper对象并持有这个对象的引用,然后调用Looper.loop()开启Looper的无限循环。

Looper#loop()

//该方法执行在调用次方法的线程中,也就是HandlerThead.
    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 (;;) {
		    //不停的从MessageQueue取出message
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
		  //省略部分代码
            try {
			//一旦message不为空则交由handler处理这个消息。
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
        }
    }

从上面代码可以看出,Looper从MessageQuene中获取到messge之后交给message的目标handler处理这个message。因为Looper#loop()在HandlerThread线程中执行,所以handler的处理过程也是在HandlerThread线程中执行。

2.2 生成一个handler绑定HandlerThread生成的Looper对象

threadHandler = new Handler(thread.getLooper()){
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    //子线程handler接收到消息,开始处理任务
                    collectInfo("threadHandler接收到消息开始处理");
                    SystemClock.sleep(2000);
                    //告诉UI handler任务完成的消息
                    collectInfo("子线程处理好任务了");
                }
            };

在这个threadHandler对象的handleMessage()方法中处理Looper传过来的Message。由于Looper#loop()在HandlerThread线程中执行,所以handler的handleMessage处理过程也是在HandlerThread线程中执行

2.3 我们在主线程中调用threadHanlder的发送message的方法

threadHandler.obtainMessage(1).sendToTarget();

此时发动消息是执行在主线程的,我们看下发送的代码流程:

Handler#obtainMessage

 public final Message obtainMessage(int what)
    {
        return Message.obtain(this, what);
    }

Message#obtain

public static Message obtain(Handler h, int what) {
        Message m = obtain();
        m.target = h;
        m.what = what;

        return m;
    }

Message#sendToTarget

/**
     * Sends this Message to the Handler specified by {@link #getTarget}.
     * Throws a null pointer exception if this field has not been set.
     */
    public void sendToTarget() {
        target.sendMessage(this);
    }

target是Handler,此时又回到了handler#sendMessage

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


 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

我们继续看一下MessageQuene#enqueueMessage

boolean enqueueMessage(Message msg, long when) {
       //省略部分代码
        synchronized (this) {
            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }
			//省略部分代码
        }
        return true;
    }

从代码可以看出,此方法就是把消息按照时间顺序放入MessageQuene中(此时是在主线程执行)等待被Looper.loop()的无限循环获取方法取出并传给handler处理(此时是在HandlerThread线程中执行)。至此消息在主线程生成在HandlerThread线程被执行的过程就完成了。

完整的演示demo代码地址:https://github.com/zhaohe9981/HandlerToggleThread.git

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值