概述
Handler消息机制-FWK层
android12-release
1. 功能简介概要
1.1 简介概要
frameworks/base/core/java/android/os/Handler.java
frameworks/base/core/java/android/os/Looper.java
frameworks/base/core/java/android/os/MessageQueue.java
frameworks/base/core/java/android/os/Message.java
Activity中UI组件中的信息传递Handler,Android为了线程安全,并不允许我们在UI线程外操作UI;很多时候我们做界面刷新都需要通过Handler来通知UI组件更新!除了用Handler完成界面更新外,还可以使用runOnUiThread()来更新,甚至更高级的事务总线,当然,这里我们只讲解Handler。
当我们的子线程想修改Activity中的UI组件时,我们可以新建一个Handler对象,通过这个对象向主线程发送信息;而我们发送的信息会先到主线程的MessageQueue进行等待,由Looper按先入先出顺序取出,再根据message对象的what属性分发给对应的Handler进行处理!
Handler
: 作用就是发送与处理信息,如果希望Handler正常工作,在当前线程中要有一个Looper对象Message
: Handler接收与处理的消息对象MessageQueue
: 消息队列,先进先出管理Message,在初始化Looper对象时会创建一个与之关联的MessageQueueLooper
: 每个线程只能够有一个Looper,管理MessageQueue,不断地从中取出Message分发给对应的Handler处理
1.2 使用案例
UI线程就是我们的主线程,系统在创建Activity UI线程的时候会初始化一个Looper对象,同时也会创建一个与其关联的MessageQueue
public class MainActivity extends Activity {
final Handler myHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
子线中使用需要先执行Looper.prepare()
初始化一个Looper对象,Looper的构造方法中会创建一个MessageQueue对象,再将Looper对象保存到当前线程TLS(Thread Local Storage)。Looper.prepare()在每个线程只允许执行一次。
class SubThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
//TODO 定义消息处理逻辑.
}
};
Looper.loop();
}
}
1.2.1 UI线程初始化Looper
Looper.prepareMainLooper()
在fork创建创建进程回调ActivityThread.main()
,Activity UI线程初始化一个Looper对象
- prepare(false)表示当前Looper不允许退出,也就是主线的Looper是不允许退出;
prepare()
默认调用prepare(true),表示的是这个Looper允许退出。
frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {
// ... ...
Looper.prepareMainLooper();
// ... ...
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
1.3 大致流程
2. 流程分析
2.1 相关类之间大致关系
- Handler包含Loooper和MessageQueue
- Looper包含MessageQueue
- MessageQueue包含Message;这里需要关注
mPtr = nativeInit()
,连接Native层 - Message包含Handler,使用
Handler.obtainMessage()
获取
2.2 obtainMessage获取Message
上面1.2 使用案例说过初始化注意事项,这里说一下Message获取
在使用Handler时,通常是通过Handler.obtainMessage()
来获取Message对象的,而其内部调用的是Message.obtain()方法,那么问题来了,为什么不直接new一个Message,而是通过Message的静态方法obtain()来得到的呢?
使用obtain获取Message对象是因为Message内部维护了一个数据缓存池,回收的Message不会被立马销毁,而是放入了缓存池,在获取Message时会先从缓存池中去获取,缓存池为null才会去创建新的Message。
这里也会把Handler给到Message,如果缓存池为null或直接
new Message()
,Message中变量target:Handler
也会在Handler.sendMessage(msg)
是赋值
2.3 消息发送sendMessage、Looper.loop处理目标handler.dispatchMessage
Handler消息发送最终都会调用
MessageQueue.enqueueMessage()
:handler.sendMessage --> sendMessageDelayed --> sendMessageAtTime --> enqueueMessage --> queue.enqueueMessage
loop()进入循环模式,不断重复下面的操作,直到没有消息时退出循环
- 读取MessageQueue的下一条Message;
- 把Message分发给相应的Handler target;
msg.recycleUnchecked()
把分发后的Message回收到消息池,以便重复利用。
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride) {
Message msg = me.mQueue.next(); // might block
// ... ...
final Observer observer = sObserver;
// ... ...
if (observer != null) {
token = observer.messageDispatchStarting();
}
long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
try {
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
if (observer != null) {
observer.dispatchingThrewException(token, msg, exception);
}
throw exception;
} finally {
// ... ...
}
// ... ...
msg.recycleUnchecked();
return true;
}
2.4 Looper唤醒(MessageQueue连接Native层)
- sendMessage时可以触发
nativeWake(mPtr)
Message msg = me.mQueue.next()
loop() 获取MessageQueue队列消息时触发先触发nativePollOnce(ptr, nextPollTimeoutMillis)
阻塞操作
通过MessageQueue调用native层中执行
mLooper->wake()
唤醒
frameworks/base/core/java/android/os/Handler.java
frameworks/base/core/java/android/os/MessageQueue.java
boolean enqueueMessage(Message msg, long when) {
// ... ...
synchronized (this) {
// ... ...
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
frameworks/base/core/java/android/os/Looper.java
frameworks/base/core/java/android/os/MessageQueue.java
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride) {
Message msg = me.mQueue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return false;
}
// ... ...
}
Message next() {
// ... ...
for (;;) {
// ... ...
nativePollOnce(ptr, nextPollTimeoutMillis);
// ... ...
}
}
2.4 removeMessages移除Message
- 最终执行
Message.recycleUnchecked()
;Message没有立马销毁,而是放入了缓存池sPool
,缓存池大小MAX_POOL_SIZE = 50
,在获取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 = UID_NONE;
workSourceUid = UID_NONE;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
3. MessageQueue连接Native层 待续~
再次整体查看下大致流程
最后
以上就是淡淡路人为你收集整理的Handler消息机制-FWK层Handler消息机制-FWK层的全部内容,希望文章能够帮你解决Handler消息机制-FWK层Handler消息机制-FWK层所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复