了解Handler,Looper, MessageQueue,Message的工作流程

发布时间:2020-10-06 12:57:57 作者:墨宇hz
来源:网络 阅读:639

Handler的作用

异步通信,消息传递

Handler的基本用法

Handler的用法,示例1、(子线程向主线程发送消息)

public class HandlerActivity extends AppCompatActivity {
Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        Toast.makeText(HandlerActivity.this, "接收到了消息", Toast.LENGTH_SHORT).show();
    }
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_handler);

}

public void onClickView(View v) {
    switch (v.getId()) {
        case R.id.button: {
            Thread thread = new Thread() {
                @Override
                public void run() {
                    Message msg = Message.obtain();
                    handler.sendMessage(msg);
                }
            };
            thread.start();
            break;
        }
    }
}
}

这个界面只有一个Button, 点击事件是:启动一个线程,在这个线程里使用handler,发送一个消息;这个消息不带任何数据。
Message: 这个可以使用new来生成,但是最好还是使用Message.obtain()来获取一个实例。这样便于消息池的管理。
handler初始化的时候,我们复写了handleMessage方法,这个方法用来接收,子线程中发过来的消息。

示例2、主线程向子线程发送消息

public class HandlerActivity extends AppCompatActivity {
Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        Log.d("child", "----" + Thread.currentThread().getName());
    }
};
Handler childHandler = null;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_handler);
    Thread child = new Thread("child thread") {
        @Override
        public void run() {
            Looper.prepare();
            childHandler = new Handler(Looper.myLooper()) {
                @Override
                public void handleMessage(Message msg) {
                    Log.d("child", "----" + Thread.currentThread().getName() + ",  " + msg.obj);
                }
            };
            Looper.loop();
        }
    };
    child.start();
}

public void onClickView(View v) {
    switch (v.getId()) {
        case R.id.button: {
            Thread thread = new Thread() {
                @Override
                public void run() {
                    Message msg = Message.obtain();
                    handler.sendMessage(msg);
                }
            };
            thread.start();
            break;
        }
        case R.id.button1: {
            if (childHandler != null) {
                Message msg = Message.obtain(childHandler);
                msg.obj = "123---" + SystemClock.uptimeMillis();
                childHandler.sendMessage(msg);

            } else {
                Log.d("-----", "onClickView: child Handler is null");
            }

            break;
        }
    }
}
}

主线程向子线程发送消息时,我们需要使用的是handler,但是这个handler是需要在子线程中实例化,否则子线程无法接收到消息。
在child thread中准备的工作:

这个方法里面,我们需要注意到:

  1. Looper me这个不允许为空
  2. for (;;)循环
  3. Message msg = queue.next()
  4. msg.target.dispatchMessage(msg);

  5. 在looper.loop方法里面,检查了本线程中的Looper实例,也对应了在调用looper.loop方法之前必须先调用looper.prepare方法。
  6. for循环是一个死循环,这个需要一直取出MessageQueue队列中的数据,也就是刚才所列的第三个 queue.next方法。这个方法会阻塞,直到有消息从消息队列中取出来。
    next方法源码:

    Message next() {
    // Return here if the message loop has already quit and been disposed.
    // This can happen if the application tries to restart a looper after quit
    // which is not supported.
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }
    int pendingIdleHandlerCount = -1; // -1 only during first iteration
    int nextPollTimeoutMillis = 0;
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }
    
        nativePollOnce(ptr, nextPollTimeoutMillis);
    
        synchronized (this) {
            // Try to retrieve the next message.  Return if found.
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            if (msg != null && msg.target == null) {
                // Stalled by a barrier.  Find the next asynchronous message in the queue.
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                if (now < msg.when) {
                    // Next message is not ready.  Set a timeout to wake up when it is ready.
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // Got a message.
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    return msg;
                }
            } else {
                // No more messages.
                nextPollTimeoutMillis = -1;
            }
    
            // Process the quit message now that all pending messages have been handled.
            if (mQuitting) {
                dispose();
                return null;
            }
    
            // If first time idle, then get the number of idlers to run.
            // Idle handles only run if the queue is empty or if the first message
            // in the queue (possibly a barrier) is due to be handled in the future.
            if (pendingIdleHandlerCount < 0
                    && (mMessages == null || now < mMessages.when)) {
                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(TAG, "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;
    }

    }

  7. queue.next方法,返回一个Message,而这个message会被传入到msg.target的dispatchMessage方法中。msg.target是一个handler,就是发送消息的实例。
    dispatchMessage(Message)源码:
    public void dispatchMessage(Message msg) {<br/>if (msg.callback != null) {<br/>handleCallback(msg);<br/>} else {<br/>if (mCallback != null) {<br/>if (mCallback.handleMessage(msg)) {<br/>return;<br/>}<br/>}<br/>handleMessage(msg);<br/>}<br/>}<br/>
    Handler初始化的时候,我们并没有传入msg.callback和mCallback这两个回调。所以这个方法最终执行的是handleMessage方法。
    上面我们分析了ThreadLocal,Looper,Message,MessageQueue,下面开始分析handler发送消息的方式。

    Handler发送消息

    Handler 通过sendMessage方法发送消息。这个方法最终调用的是

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {<br/>msg.target = this;<br/>if (mAsynchronous) {<br/>msg.setAsynchronous(true);<br/>}<br/>return queue.enqueueMessage(msg, uptimeMillis);<br/>}<br/>
参数:MessageQueue queue则是Handler中mQueue变量,这个变量在Handler(Callback callback, boolean async)初始化完成。它是Looper中一个final MessageQueue的变量,在初始化Looper的时候,就开始初始化MessageQueue。这也是一个线程中只有一个MessageQueue的原因.
Message msg 是封装的消息。
long uptimeMillis 延迟发送时间。
之前分析looper.loop方法的时候,说了msg.target.dispatchMessage, 这个target就是在这个方法里面赋值的。
从这个方法里面,可以知道handler的sendMessage,只是把消息(Message实例)添加到了queue队列中。

    boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) {
        throw new IllegalArgumentException("Message must have a target.");
    }
    if (msg.isInUse()) {
        throw new IllegalStateException(msg + " This message is already in use.");
    }
    synchronized (this) {
        if (mQuitting) {
            IllegalStateException e = new IllegalStateException(
                    msg.target + " sending message to a Handler on a dead thread");
            Log.w(TAG, e.getMessage(), e);
            msg.recycle();
            return false;
        }

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

        // We can assume mPtr != 0 because mQuitting is false.
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

Handler, Looper, Message, MessageQueue之间的关系

通过handler发送Message,将Message压入MessageQueue队列中;而Looper.loop方法又在不停的循环这个消息队列,取出压入MessageQueue的Message, 然后dispatchMessage分发,最终会调用handler.handleMessage方法来处理发送过来的Message.

推荐阅读:
  1. 从架构师的角度分析Android Handler 源码的正确姿势
  2. Handler的解析和使用

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

handler message queue

上一篇:微信小程序indexOf的替换方法(推荐)

下一篇:Vue中自定义全局组件的实现方法

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》