目录
本篇探究 Android framework native层多媒体库中的 AHandler+ALooper+AMessage 这三个类的关系和机制,并借鉴此原理,用c++(c++17)重新实现自己的Handler+Looper+Message. 实现可以支持异步和同步的消息处理结构。
android里面的这三个类 在 /frameworks/av/media/libstagefright/foundation
可以在如下 在线 aosp源码找到 http://www.aospxref.com/android-12.0.0_r3/xref/frameworks/av/media/libstagefright/foundation/
android中取名在前面加了个前缀 A, 表示android.
基于此重新用c++写的 CHandler CLooper CMessage ,在个人的github:https://github.com/Canok7/openScreen/commit/74ae413b916d66a87f27f9c614ab2b2f26104635
looper 为主循环,内部存在一个消息链表,存储着这个消息和该消息应该被处理的时间点,该链表插入消息的时候有序插入,是确保消息是按照消息的处理时间的先后来进行排序的,循环体不停地从链表中取出最先需要处理的消息,如果没有消息,进入条件等待,如果有就调用消息的所绑定的目标hander的onMessageReceived函数。 所以核心即按执行时间排序的消息链表和线程条件等待机制。
1. 建一个looper 调用start() 。也可以给looper设置线程名称,方便调试
- std::shared_ptr
mSink_Loop = std::make_shared(); - mSink_Loop->setName("test_looper");
- mSink_Loop->start();
2. 建一个自定义的Handler,将其注册到looper .(注册到looper有两个作用,一是绑定looper和hander的对应关系,后续Message即可通过handler来找到looper,二是要确保一个hander只能被注册一次,不能绑定到多个looper上去,所以源码里面有LooperRoster,它用一张map表记录有所有的handler和looper对应关系。 这个对象是全局唯一的,即一个进程中只有一个LooperRoster)
- class LooperTest : public CHandler{
- public:
- enum{
- MSG_SAY,
- MSG_SUM,
- };
- LooperTest() = default;
- virtual ~LooperTest() = default;
- void onMessageReceived(const std::shared_ptr
&msg) override{ - switch (msg->what()) {
- case MSG_SAY:
- {
- std::string say_Str;
- int32_t say_Int=0;
- CHECK(msg->findString("say_Str", &say_Str));
- CHECK(msg->findInt32("say_Int", &say_Int));
- ALOGD("[%s%d](%d) say_Str.c_str():%s,say_Int:%d\n",__FUNCTION__,__LINE__,gettid(),say_Str.c_str(),say_Int);
- }
- break;
- case MSG_SUM:
- {
- //get reply from msg
- std::shared_ptr
replyID; - CHECK(msg->senderAwaitsResponse(&replyID));
-
- //do work
- int32_t add1=0,add2=0;
- msg->findInt32("add1", &add1);
- msg->findInt32("add2", &add2);
- ALOGD("[%s%d](%d) to sum:%d,%d\n",__FUNCTION__,__LINE__,gettid(),add1,add2);
-
- //post resut
- std::shared_ptr
response = std::make_shared(); - response->setInt32("result", add1+add2);
- response->postReply(replyID);
- }
- break;
- default:
- ALOGD("unKnow msg:%d\n",msg->what());
- break;
- }
- }
- };
- enum{
- TEST_THREAD,
- TEST_SP,
- TEST_LOOPER,
- TEST_ABUFFER_LIST,
- };
-
- //
- std::shared_ptr
mHander = std::make_shared(); - mSink_Loop->registerHandler(mHander);
3. 建一个Message, 设定message 的Handler 和what.(可以直接在构造函数中携带) 调用异步处理post(只管把消息发出去,不管结果),或者同步postAndAwaitResponse(把消息发出去,并且阻塞在这里等待返回结果)
- //异步
- std::shared_ptr
msg = std::make_shared(LooperTest::MSG_SAY,mHander); - msg->setString("say_Str", "hello");
- msg->setInt32("say_Int", count++);
- msg->post();
-
- //同步等待
- std::shared_ptr
msg = std::make_shared(LooperTest::MSG_SUM,mHander); - msg->setInt32("add1", 7);
- msg->setInt32("add2", 8);
- ALOGD("[%s%d](%d) postAndAwaitResponse\n",__FUNCTION__,__LINE__,gettid());
- std::shared_ptr
response; - //this will make a reply,and wait !!
- status_t err = msg->postAndAwaitResponse(&response);
- ALOGD("[%s%d] -----debug %d err ",__FUNCTION__ ,__LINE__,err);
- if (err == OK) {
- int ret=0;
- response->findInt32("result", &ret);
- ALOGD("[%s%d]xxxxxxxxxxxx(%d) get add ret:%d\n",__FUNCTION__,__LINE__,gettid(),ret);
- }
1. 为了保证所有的Handler只会被绑定到一个Looper, 这里有一个单例的LooperRoster . 调试的时候可以从LooperRoster中看到所有已注册的looper和Handler. 外部register的时候如果Handler已经被注册,register将不成功。
2. Message持有Looper Handler , Handler持有Looper, 存储的都是weak_ptr, 如果某个Handler已经被释放,looper循环体在处理和这个Handler对应的消息时会忽略这个Message,不会发生错误。
3. 调用者往Looper里面注册Handler, 相应地也应该需要调用反注册的机制,但是如果忘了没用调用反注册(registerHandler/unregisterHandler),也不会发生错误,在Looper的构造函数中会调用gLooperRoster.unregisterStaleHandlers()候判断哪一些handler已经是被析构了,然后去掉这些已经析构的无效Handler.