1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 【Android】线程间通信——Handler消息机制

【Android】线程间通信——Handler消息机制

时间:2019-07-01 22:32:47

相关推荐

【Android】线程间通信——Handler消息机制

文章目录

引言Java层永动机跑起来示例LooperHandlerMessageQueue永动机停下Native层nativeInit()nativePollOnce()nativeWake()native层总结创建Hanler线程

引言

Binder/Socket用于进程间通信,而Handler消息机制用于同进程的线程间通信,Handler消息机制是由一组MessageQueue、Message、Looper、Handler共同组成的,为了方便且称之为Handler消息机制。

Handler实例对象mHandler位于线程间共享的内存堆上,工作线程与主线程都能直接使用该对象,只需要注意多线程的同步问题。工作线程通过mHandler向其成员变量MessageQueue中添加新Message,主线程一直处于loop()方法内,当收到新的Message时按照一定规则分发给相应的handleMessage()方法来处理。所以说,Handler消息机制用于同进程的线程间通信,其核心是线程间共享内存空间,而不同进程拥有不同的地址空间,也就不能用handler来实现进程间通信。

Java层

永动机跑起来

Message:消息分为硬件产生的消息(如按钮、触摸)和软件生成的消息;MessageQueue:消息队列(按时间的优先级队列)的主要功能向消息池投递消息(MessageQueue.enqueueMessage)和取走消息池的消息(MessageQueue.next);Handler:消息辅助类,主要功能向消息池发送各种消息事件(Handler.sendMessage)和处理相应消息事件(Handler.handleMessage);Looper:不断循环执行(Looper.loop),按分发机制将消息分发给目标处理者。

enqueueMessage()中msg.target = this; 导致msg持有handler,而handler持有activity(内部类持有外部类的对象),而msg又在外部类的生命周期内。导致内存泄漏

示例

class LooperThread extends Thread {public Handler mHandler;public void run() {Looper.prepare(); //【见 2.1】mHandler = new Handler() {//【见 3.1】public void handleMessage(Message msg) {//TODO 定义消息处理逻辑. 【见 3.2】}};Looper.loop(); //【见 2.2】}}

Looper

Looper.prepare()

保证looper线程唯一:ThreadLocal

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();final MessageQueue mQueue; //优先级消息队列

Handler

(1)消息发送

所有的发消息方式,最终都是调用MessageQueue.enqueueMessage();

(2)消息分发机制

在Looper.loop()中,当发现有消息时,调用消息的目标handler,执行dispatchMessage()方法来分发消息。

消息分发优先级:

MessageQueue

MessageQueue是消息机制的Java层和C++层的连接纽带,大部分核心方法都交给native层来处理

next()方法中,nativePollOnce是阻塞操作,其中nextPollTimeoutMillis代表下一个消息到来前,还需要等待的时长;当nextPollTimeoutMillis = -1时,表示消息队列中无消息,会一直等待下去。

永动机停下

loop死循环的退出

Message msg = me.mQueue.next(); // might blockif (msg == null) {// No message indicates that the message queue is quitting.return false;}

// Process the quit message now that all pending messages have been handled.if (mQuitting) {dispose();return null;}

MessageQueue的quit()方法将mQuitting=true

Message msg = me.mQueue.next(); // might block 有两种情况时间没到:计算时间后等待自动唤醒 nativePollOnce(ptr, nextPollTimeoutMillis);消息队列为空:加入消息时enqueueMessage()->唤醒 nativeWake(mPtr);

要是子线程消息队列没有消息,则手动调用quite():唤醒线程 next()返回null-》退出loop

Native层

在整个消息机制中,而MessageQueue是连接Java层和Native层的纽带,换言之,Java层可以向MessageQueue消息队列中添加消息,Native层也可以向MessageQueue消息队列中添加消息

MessageQueue中的native方法如下

nativeInit()

初始化

nativePollOnce()

提取消息队列中的消息

调用Looper::pollOnce()来完成,空闲时停留在epoll_wait()方法,用于等待事件发生或者超时

nativeWake()

nativeWake用于唤醒功能,在添加消息到消息队列enqueueMessage(), 或者把消息从消息队列中全部移除quit(),再有需要时都会调用 nativeWake方法

native层总结

MessageQueue通过mPtr变量保存NativeMessageQueue对象,从而使得MessageQueue成为Java层和Native层的枢纽,既能处理上层消息,也能处理native层消息

创建Hanler线程

1.利用HandlerThread创建

既然涉及多个线程的通信,会有同步的问题,Android为了简化Handler的创建过程,提供了HandlerThread类, 很多时候,在HandlerThread线程中运行Loop()方法,在其他线程中通过Handler发送消息到HandlerThread线程。通过wait/notifyAll的方式,有效地解决了多线程的同步问题。

// Step 1: 创建并启动HandlerThread线程,内部包含LooperHandlerThread handlerThread = new HandlerThread("");handlerThread.start();// Step 2: 创建HandlerHandler handler = new Handler(handlerThread.getLooper());// Step 3: 发送消息handler.post(new Runnable() {@Overridepublic void run() {System.out.println("thread id="+Thread.currentThread().getId());}});

2.直接创建线程

class LooperThread extends Thread {public Handler mHandler;public void run() {Looper.prepare();// Step 1: 创建HandlermHandler = new Handler() {public void handleMessage(Message msg) {//处理即将发送过来的消息System.out.println("thread id="+Thread.currentThread().getId());}};Looper.loop();}}// Step 2: 创建并启动LooperThread线程,内部包含LooperLooperThread looperThread = new LooperThread("");looperThread.start();// Step 3: 发送消息LooperThread.mHandler.sendEmptyMessage(10);

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。