目录
概述
源
自实现
下面简单叙述其原理:
如何使用:
注意问题:
概述
本篇探究 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_ptrmSink_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:%dn",__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,%dn",__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:%dn",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_ptrmsg = 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) postAndAwaitResponsen",__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:%dn",__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.