目录
概述
本篇探究 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<CLooper> mSink_Loop = std::make_shared<CLooper>();
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<CMessage> &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<CReplyToken> 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<CMessage> response = std::make_shared<CMessage>();
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<LooperTest> mHander = std::make_shared<LooperTest>();
mSink_Loop->registerHandler(mHander);
3. 建一个Message, 设定message 的Handler 和what.(可以直接在构造函数中携带) 调用异步处理post(只管把消息发出去,不管结果),或者同步postAndAwaitResponse(把消息发出去,并且阻塞在这里等待返回结果)
//异步
std::shared_ptr<CMessage> msg = std::make_shared<CMessage>(LooperTest::MSG_SAY,mHander);
msg->setString("say_Str", "hello");
msg->setInt32("say_Int", count++);
msg->post();
//同步等待
std::shared_ptr<CMessage> msg = std::make_shared<CMessage>(LooperTest::MSG_SUM,mHander);
msg->setInt32("add1", 7);
msg->setInt32("add2", 8);
ALOGD("[%s%d](%d) postAndAwaitResponse\n",__FUNCTION__,__LINE__,gettid());
std::shared_ptr<CMessage> 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.