• Android native层Hander原理分析


    目录

    概述

    自实现

    下面简单叙述其原理:

    如何使用:

    注意问题:


    概述

    本篇探究 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设置线程名称,方便调试

    1. std::shared_ptr mSink_Loop = std::make_shared();
    2. mSink_Loop->setName("test_looper");
    3. mSink_Loop->start();

    2. 建一个自定义的Handler,将其注册到looper .(注册到looper有两个作用,一是绑定looper和hander的对应关系,后续Message即可通过handler来找到looper,二是要确保一个hander只能被注册一次,不能绑定到多个looper上去,所以源码里面有LooperRoster,它用一张map表记录有所有的handler和looper对应关系。 这个对象是全局唯一的,即一个进程中只有一个LooperRoster)

    1. class LooperTest : public CHandler{
    2. public:
    3. enum{
    4. MSG_SAY,
    5. MSG_SUM,
    6. };
    7. LooperTest() = default;
    8. virtual ~LooperTest() = default;
    9. void onMessageReceived(const std::shared_ptr &msg) override{
    10. switch (msg->what()) {
    11. case MSG_SAY:
    12. {
    13. std::string say_Str;
    14. int32_t say_Int=0;
    15. CHECK(msg->findString("say_Str", &say_Str));
    16. CHECK(msg->findInt32("say_Int", &say_Int));
    17. ALOGD("[%s%d](%d) say_Str.c_str():%s,say_Int:%d\n",__FUNCTION__,__LINE__,gettid(),say_Str.c_str(),say_Int);
    18. }
    19. break;
    20. case MSG_SUM:
    21. {
    22. //get reply from msg
    23. std::shared_ptr replyID;
    24. CHECK(msg->senderAwaitsResponse(&replyID));
    25. //do work
    26. int32_t add1=0,add2=0;
    27. msg->findInt32("add1", &add1);
    28. msg->findInt32("add2", &add2);
    29. ALOGD("[%s%d](%d) to sum:%d,%d\n",__FUNCTION__,__LINE__,gettid(),add1,add2);
    30. //post resut
    31. std::shared_ptr response = std::make_shared();
    32. response->setInt32("result", add1+add2);
    33. response->postReply(replyID);
    34. }
    35. break;
    36. default:
    37. ALOGD("unKnow msg:%d\n",msg->what());
    38. break;
    39. }
    40. }
    41. };
    42. enum{
    43. TEST_THREAD,
    44. TEST_SP,
    45. TEST_LOOPER,
    46. TEST_ABUFFER_LIST,
    47. };
    48. //
    49. std::shared_ptr mHander = std::make_shared();
    50. mSink_Loop->registerHandler(mHander);

    3. 建一个Message, 设定message 的Handler 和what.(可以直接在构造函数中携带)  调用异步处理post(只管把消息发出去,不管结果),或者同步postAndAwaitResponse(把消息发出去,并且阻塞在这里等待返回结果)
     

    1. //异步
    2. std::shared_ptr msg = std::make_shared(LooperTest::MSG_SAY,mHander);
    3. msg->setString("say_Str", "hello");
    4. msg->setInt32("say_Int", count++);
    5. msg->post();
    6. //同步等待
    7. std::shared_ptr msg = std::make_shared(LooperTest::MSG_SUM,mHander);
    8. msg->setInt32("add1", 7);
    9. msg->setInt32("add2", 8);
    10. ALOGD("[%s%d](%d) postAndAwaitResponse\n",__FUNCTION__,__LINE__,gettid());
    11. std::shared_ptr response;
    12. //this will make a reply,and wait !!
    13. status_t err = msg->postAndAwaitResponse(&response);
    14. ALOGD("[%s%d] -----debug %d err ",__FUNCTION__ ,__LINE__,err);
    15. if (err == OK) {
    16. int ret=0;
    17. response->findInt32("result", &ret);
    18. ALOGD("[%s%d]xxxxxxxxxxxx(%d) get add ret:%d\n",__FUNCTION__,__LINE__,gettid(),ret);
    19. }

    注意问题:

            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.

  • 相关阅读:
    计算机毕业设计Java校园旺角超市外卖平台(源码+系统+mysql数据库+Lw文档)
    Redis Java整合
    linux常用命令收集
    VSCode 最好的 Python 扩展,可大大提升你的生产力
    【Linux】指令详解(一)
    开源在线表单工具 HeyForm 使用教程
    信息检索与数据挖掘 | 【实验】排名检索模型
    单链表结点的删除(思路分析) [数据结构][Java]
    shell脚本
    猫头虎分享从Python到JavaScript传参数:多面手的数据传递术
  • 原文地址:https://blog.csdn.net/u012459903/article/details/126191470