Handler,Looper,MessageQueue

结论:一个线程可以有多个Handler,只有一个Looper,只有一个MessageQueue。多个Handler共用一个Looper和一个MessageQueue。一个应用中可以有多个Handler,多个Looper,多个MessageQueue。

  1. 一个线程可以有多个Handler

这个很好理解,你在Activity中,new 多少个Handler都不会出问题,而且每个Handler都有sendMessage

2.假如一个线程可以有多个Looper

大家都知道UI线程系统会默认帮我们创建一个Looper对象,这样每次我们创建Handler时候,就不用自己去调用Looper.prepare(),Looper.loop()方法。如果多个Looper可以在一个线程中,那么应用完全只可以自己创建一个Looper,这样加上系统创建的,就会有两个Looper对象。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
		Looper.prepare();
        mHandler = new Handler(mThread.getLooper()){
            @Override
            public void handleMessage(Message msg) {

                super.handleMessage(msg);
            }
        };
}

上述代码运行会出现RuntimeException

已经说得很明白,每个线程只能有一个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));
}

先从sThreadLocal中获取,如果获取到了,说明已经存在对应的Looper对象,直接抛异常。没有则创建新的Looper,然后存到sThreadLocal中。

  1. 一个线程只有一个MessageQueue

这个要从源码的角度看,Handler两个主要的构造方法

    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
	
	
	    public Handler(Callback callback, boolean async) {
        . . .
        mLooper = Looper.myLooper();
        . . .
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
}

可以看到mQueue 是从对应的Looper对象中获取到的。上面已经说明一个线程只能有一个Looper存在,那么MessageQueue也只能有一个。所有的Handler共用Looper和MessageQueue。

如果多个Handler共用一个MessageQueue,那么Looper如何知道将这个Message发送到哪个Handler呢?

public final class Message implements Parcelable {

    public int what;

    public int arg1;


    public int arg2;

    public Object obj;
...
    /*package*/ Handler target;

在Message中都会有一个Handler对象,叫做target,也就是发送该Mesaage的Handler对象,所以不同的Message里面的tartget可能是不用的,所以Looper轮训到这个Message后,就可以根据这个tartget进行分发处理。

常用的发送消息方式:

mHandler.sendEmptyMessage(0);

mHandler.sendEmptyMessageDelayed(0,1000);

其实sendEmptyMessage也调用的sendEmptyMessageDelayed

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

创建一个Message,然后将我们传递的what设置到对应的Message上

public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

如果传递的时间小于0那么设置为0,如果大于0,获取系统时间 + 上要 延迟的时间。

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

如果没有MessageQueue,会报错,然后将Message放入队列

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;//关键一步,Message持有当前Handler的引用
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}
Message msg = new Message();
mHandler.sendMessage(msg);
Message msg = Message.obtain();
mHandler.sendMessage(msg);

直接new一个Message发送,也会调用sendMessageDelayed最终Message也会持有当前Handler的引用。

public final boolean sendMessage(Message msg)
{
    return sendMessageDelayed(msg, 0);
}

只要你使用sendMessageXXX,Handler都会在Message上将自己设置为target。

看一下Looper轮询消息,是如何处理的:

  public static void loop() {
        final Looper me = myLooper();获取到Looper
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;获取到MessageQueue

......

        for (;;) {
            Message msg = queue.next(); // 循环获取nextMessage
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

.......

            try {
                msg.target.dispatchMessage(msg);发送给对应的target(Handler)的dispathMessage方法
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
               
            }
....
            msg.recycleUnchecked();回收对应的Mesaage
        }
    }

Handler 的dispathMessage,调用自己的handleMessage方法

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

回收Message

void recycleUnchecked() {
    // Mark the message as in use while it remains in the recycled object pool.
    // Clear out all other details.
    flags = FLAG_IN_USE;
    what = 0;
    arg1 = 0;
    arg2 = 0;
    obj = null;
    replyTo = null;
    sendingUid = -1;
    when = 0;
    target = null;
    callback = null;
    data = null;

    synchronized (sPoolSync) {
        if (sPoolSize < MAX_POOL_SIZE) {
            next = sPool;
            sPool = this;
            sPoolSize++;
        }
    }
}

Handler的handleMessage是运行在主线程还是子线程,是谁决定的?答案是Looper

在主线程中,系统默认帮我们创建了Looper,在子线程中,我们也可以创建自己的Looper,创建的方式就是调用Looper.prepare();

public static void prepare() {
    prepare(true);
}
private static void prepare(boolean quitAllowed) {
//首先获取,如果对应的Looper存在,抛异常,一个线程只能有一个Looper
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
如果没有,创建并存入sThreadLocal中,
    sThreadLocal.set(new Looper(quitAllowed));
}

在创建Looper的时候,创建了该Looper对应的MessageQueue

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

所以说,当你在主线程调用prepare时,你的handleMessage运行在主线程,如果你是在子线程中调用的prepare,那么你的handleMessage方法,是运行在子线程中的。也就是说你的Looper是在哪个线程创建的,你的handleMessage就是在哪个线程执行。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值