Handler任务模型之MessageQueue

1. 介绍
在之前的篇幅中介绍了Handler任务模型中Message类和Looper类的源码分析,本篇将分析Handler类和Message类。

2. 源码分析

  • Handler类
    之前 Handler任务模型之Looper类分析得到博乐评论说应该从使用开始到源码分析,这样可以使条理更加清晰,所以咱们先看下Handler的使用
private Handler handler = new Handler() {

        public void handleMessage(android.os.Message msg) {
            //.................
        };
    };
Message msg = Message.obtain();
        msg.what = 0;
        handler.sendMessage(msg);

我们一般是这样使用Handler的,首先谈下Handler的构造,Handler类本身提供了四种构造方法

public Handler() {
        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 = null;
    }
public Handler(Callback callback) {
        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;
    }
 public Handler(Looper looper) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = null;
    }
 public Handler(Looper looper, Callback callback) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
    }

四种构造函数主要是为了三个变量赋值,第一个是mLooper,第二个是mQueue,第三个是mCallBack。
其中Looper是一个循环体,MessageQueue保持着Message消息链的引用,mCallBack提供一个回调方法在handlerMessage之前执行。
Handler类本身提供了很多的发送消息的方法和post的方法
这里写图片描述
这些方法内部最后都是同一调用sendMessageAtTime这个方法

 public boolean sendMessageAtTime(Message msg, long uptimeMillis)
    {
        boolean sent = false;
        MessageQueue queue = mQueue;
        if (queue != null) {
            msg.target = this;
            sent = queue.enqueueMessage(msg, uptimeMillis);
        }
        else {
            RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
        }
        return sent;
    }

第6行:将Message的target赋值为this,可以看出一个Message对应一个Handker,谁发送的消息还要交给谁处理,只是在主线程绕一圈而已
第7行:将msg投递到消息链中

  • MessageQueue源码分析
    handler的sendMessageAtTime方法内部调用MessageQueue的enqueueMessage投递任务
   final boolean enqueueMessage(Message msg, long when) {
        if (msg.when != 0) {
            throw new AndroidRuntimeException(msg
                    + " This message is already in use.");
        }
        if (msg.target == null && !mQuitAllowed) {
            throw new RuntimeException("Main thread not allowed to quit");
        }
        final boolean needWake;
        synchronized (this) {
            if (mQuiting) {
                RuntimeException e = new RuntimeException(
                    msg.target + " sending message to a Handler on a dead thread");
                Log.w("MessageQueue", e.getMessage(), e);
                return false;
            } else if (msg.target == null) {
                mQuiting = true;
            }

            msg.when = when;
            //Log.d("MessageQueue", "Enqueing: " + msg);
            Message p = mMessages;
            if (p == null || when == 0 || when < p.when) {
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked; // new head, might need to wake up
            } else {
                Message prev = null;
                while (p != null && p.when <= when) {
                    prev = p;
                    p = p.next;
                }
                msg.next = prev.next;
                prev.next = msg;
                needWake = false; // still waiting on head, no need to wake up
            }
        }
        if (needWake) {
            nativeWake(mPtr);
        }
        return true;
    }

第2-5行:通过msg.when对消息进行校验,新消息默认是没有when赋值的,如果此时msg.when != 0说明已经执行该Message正在被使用。不能再次被添加到链表中去
第6-8行:在之前的篇幅中我们介绍过当msg.target为空作为Looper消息循环结束的一个标志位,
mQuitAllowed控制当前线程是否被允许,一般线程是被允许,因为mQuitAllowed初始值为true,但是UI主线程是不允许退出的,因为在Looper的prepareMainLooper方法中将mQuitAllowed赋值为false

 public static final void prepareMainLooper() {
        prepare();
        setMainLooper(myLooper());
        if (Process.supportsProcesses()) {
            myLooper().mQueue.mQuitAllowed = false;
        }
    }

第20 - 37行:在Message源码分析中我们可以看出Message是以链表形式存放的,当时不能看出Message之间的关系,其实Message是一个按照时间从小到大的链表形式存放的,这些代码行就是处理这些逻辑关系。
通过上面的步骤已经将Message添加消息链表中,同时Looper的loop方法会一直调用MessageQueue的next取出消息

    final Message next() {
        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;

        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }
            nativePollOnce(mPtr, nextPollTimeoutMillis);

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                final Message msg = mMessages;
                if (msg != null) {
                    final long when = msg.when;
                    if (now >= when) {
                        mBlocked = false;
                        mMessages = msg.next;
                        msg.next = null;
                        if (Config.LOGV) Log.v("MessageQueue", "Returning message: " + msg);
                        return msg;
                    } else {
                        nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE);
                    }
                } else {
                    nextPollTimeoutMillis = -1;
                }

                // If first time, then get the number of idlers to run.
                if (pendingIdleHandlerCount < 0) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount == 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    mBlocked = true;
                    continue;
                }

                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }

            // Run the idle handlers.
            // We only ever reach this code block during the first iteration.
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null; // release the reference to the handler

                boolean keep = false;
                try {
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf("MessageQueue", "IdleHandler threw exception", t);
                }

                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }

            // Reset the idle handler count to 0 so we do not run them again.
            pendingIdleHandlerCount = 0;

            // While calling an idle handler, a new message could have been delivered
            // so go back and look again for a pending message without waiting.
            nextPollTimeoutMillis = 0;
        }

第11-28行:通过判断时间是否符合条件从链表中取出消息,这里时间是按照开机时间计算的
余下的代码行是处理IdleHandler闲时回调接口,以及该回调接口是处理一次即焚还是继续调用的问题,
好像在项目中不是很常用到。
这样从MessageQueue持有的消息链中取出消息后就要回到Looper的loop方法逻辑

 public static final void loop() {
        Looper me = myLooper();
        MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        while (true) {
            Message msg = queue.next(); // might block
            //if (!me.mRun) {
            //    break;
            //}
            if (msg != null) {
                if (msg.target == null) {
                    // No target is a magic identifier for the quit message.
                    return;
                }
                msg.target.dispatchMessage(msg);
                msg.recycle();
            }
        }
    }

第16-19行:通过标志位控制Looper的退出
第20行:分发消息msg.target.dispatchMessage(msg);
这样就将消息分发给相应的Handler中,最后回调到我们重写的handleMessage方法中

3. 总结
从以上的分析我们可以看出,各个类之间的对应关系,一个Thread对应一个Looper,一个Looper对应一个MessageQueue,一个MessageQueue持有一个Message消息链,消息链中每个消息对应一个Handler,也就是一个Looper对应对个Handler对象。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值