⌈Android Native消息队列处理系列文章⌋

Android Native -- Message/Handler/Looper机制(原理篇)

Android Native -- Message/Handler/Looper机制(应用篇)


前言

上一篇中我们简单分析了Android Native Looper机制的基本运行过程,这一篇就是在此基础上给出一个具体使用的例子。通过这个例子来具体看如何发送消息,处理消息

代码

直接上代码,如下

  1. //
  2. // Copyright 2010 The Android Open Source Project
  3. //
  4. //#define LOG_NDEBUG 0
  5. #define LOG_TAG "LooperTest"
  6. #include <utils/Looper.h>
  7. #include <utils/Timers.h>
  8. #include <utils/Log.h>
  9. #include <unistd.h>
  10. #include <time.h>
  11. #include <utils/threads.h>
  12. // # of milliseconds to fudge stopwatch measurements
  13. #define TIMING_TOLERANCE_MS 25
  14. using namespace android;
  15. using namespace std;
  16. class StubMessageHandler : public MessageHandler {
  17. public:
  18. Vector<Message> messages;
  19. virtual void handleMessage(const Message& message) {
  20. ALOGD("[Thread=%d] %s message.what=%d \n", gettid(), __func__, message.what);
  21. messages.push(message);
  22. }
  23. };
  24. struct LooperThread : public Thread {
  25. public:
  26. LooperThread(Looper *looper)
  27. : mLooper(looper) {
  28. }
  29. virtual bool threadLoop() {
  30. if(mLooper == NULL)
  31. return false;
  32. int32_t ret = mLooper->pollOnce(-1);
  33. switch (ret) {
  34. case Looper::POLL_WAKE:
  35. case Looper::POLL_CALLBACK:
  36. return true;
  37. case Looper::POLL_ERROR:
  38. ALOGE("Looper::POLL_ERROR");
  39. return true;
  40. case Looper::POLL_TIMEOUT:
  41. // timeout (should not happen)
  42. return true;
  43. default:
  44. // should not happen
  45. ALOGE("Looper::pollOnce() returned unknown status %d", ret);
  46. return true;
  47. }
  48. }
  49. protected:
  50. virtual ~LooperThread() {}
  51. private:
  52. Looper *mLooper;
  53. };
  54. class CallbackHandler {
  55. public:
  56. CallbackHandler() : callbackCount(0) {}
  57. void setCallback(const sp<Looper>& looper, int fd, int events) {
  58. looper->addFd(fd, 0, events, staticHandler, this);
  59. }
  60. protected:
  61. int handler(int fd, int events) {
  62. callbackCount++;
  63. ALOGD("[Thread=%d] %s fd=%d, events=%d, callbackCount=%d\n", gettid(), __func__, fd, events, callbackCount);
  64. return 0;
  65. }
  66. private:
  67. static int staticHandler(int fd, int events, void* data) {
  68. return static_cast<CallbackHandler*>(data)->handler(fd, events);
  69. }
  70. int callbackCount;
  71. };
  72. class Pipe {
  73. public:
  74. int sendFd;
  75. int receiveFd;
  76. Pipe() {
  77. int fds[2];
  78. ::pipe(fds);
  79. receiveFd = fds[0];
  80. sendFd = fds[1];
  81. }
  82. ~Pipe() {
  83. if (sendFd != -1) {
  84. ::close(sendFd);
  85. }
  86. if (receiveFd != -1) {
  87. ::close(receiveFd);
  88. }
  89. }
  90. status_t writeSignal() {
  91. ssize_t nWritten = ::write(sendFd, "*", 1);
  92. return nWritten == 1 ? 0 : -errno;
  93. }
  94. status_t readSignal() {
  95. char buf[1];
  96. ssize_t nRead = ::read(receiveFd, buf, 1);
  97. return nRead == 1 ? 0 : nRead == 0 ? -EPIPE : -errno;
  98. }
  99. };
  100. int main(int argc, char ** argv)
  101. {
  102. // Looper的轮询处理工作在新线程中
  103. sp<Looper> mLooper = new Looper(true);
  104. sp<LooperThread> mLooperThread = new LooperThread(mLooper.get());
  105. mLooperThread->run("LooperThread");
  106. // 测试消息的发送与处理
  107. sp<StubMessageHandler> handler = new StubMessageHandler();
  108. ALOGD("[Thread=%d] sendMessage message.what=%d \n", gettid(), 1);
  109. mLooper->sendMessage(handler, Message(1));
  110. ALOGD("[Thread=%d] sendMessage message.what=%d \n", gettid(), 2);
  111. mLooper->sendMessage(handler, Message(2));
  112. sleep(1);
  113. // 测试监测fd与回调callback
  114. Pipe pipe;
  115. CallbackHandler mCallbackHandler;
  116. mCallbackHandler.setCallback(mLooper, pipe.receiveFd, Looper::EVENT_INPUT);
  117. ALOGD("[Thread=%d] writeSignal 1\n", gettid());
  118. pipe.writeSignal(); // would cause FD to be considered signalled
  119. sleep(1);
  120. mCallbackHandler.setCallback(mLooper, pipe.receiveFd, Looper::EVENT_INPUT);
  121. ALOGD("[Thread=%d] writeSignal 2\n", gettid());
  122. pipe.writeSignal();
  123. sleep(1);
  124. mLooperThread->requestExit();
  125. mLooper.clear();
  126. }

编译Android.mk,如下

  1. LOCAL_PATH:= $(call my-dir)
  2. include $(CLEAR_VARS)
  3. LOCAL_SRC_FILES := LooperTest.cpp
  4. LOCAL_SHARED_LIBRARIES := \
  5. liblog \
  6. libutils \
  7. LOCAL_C_INCLUDES := \
  8. system/core/include/cutils \
  9. LOCAL_MODULE_TAGS := optional
  10. LOCAL_MODULE := LooperTest
  11. include $(BUILD_EXECUTABLE)

运行

  • 将上面的源代码及makefile文件放到android源码环境下,执行mm编译,得到可执行档LooperTest,将其push到测试机/system/bin/LooperTest,执行 LooperTest即可
  • 可以使用 logcat -s LooperTest 抓取log查看运行情况

分析

  • StubMessageHandler : 定义消息处理程序,继承自MessageHandler,实现其中的handleMessage以处理消息
  • LooperThread:定义Looper运行的线程,在单独的子线程中不断调用pollOnce来处理消息或回调
  • CallbackHandler:定义fd事件的回调处理程序,其中实现typedef int (Looper_callbackFunc)(int fd, int events, void* data);类型的回调函数

核心处理就是如下过程:

1. 创建Looper实例,并开启一个新线程来调用poolOnce

  1. // Looper的轮询处理工作在新线程中
  2. sp<Looper> mLooper = new Looper(true);
  3. sp<LooperThread> mLooperThread = new LooperThread(mLooper.get());
  4. mLooperThread->run("LooperThread");

2. 创建消息并指定Handler,调用sendMessage发送给Looper

  1. // 测试消息的发送与处理
  2. sp<StubMessageHandler> handler = new StubMessageHandler();
  3. ALOGD("[Thread=%d] sendMessage message.what=%d \n", gettid(), 1);
  4. mLooper->sendMessage(handler, Message(1));

3. 添加监测的fd并设置回调函数

  1. Pipe pipe;
  2. CallbackHandler mCallbackHandler;
  3. mCallbackHandler.setCallback(mLooper, pipe.receiveFd, Looper::EVENT_INPUT);
  4. ALOGD("[Thread=%d] writeSignal 1\n", gettid());
  5. pipe.writeSignal(); // would cause FD to be considered signalled

4. 新线程来调用poolOnce会阻塞在epoll_wait,当收到新Message或fd events 就会唤醒,调用对应的handleMessage或callback

结语

通过上面两篇文章的学习,基本把Looper的原理及使用讲清楚了,当然受限于本人能力,可能有错误之处。

Android Native -- Message/Handler/Looper机制(应用篇)的更多相关文章

  1. Android Native -- Message/Handler/Looper机制(原理篇)

    ⌈Android Native消息队列处理系列文章⌋ Android Native -- Message/Handler/Looper机制(原理篇) Android Native -- Message ...

  2. Android消息传递之Handler消息机制

    前言: 无论是现在所做的项目还是以前的项目中,都会遇见线程之间通信.组件之间通信,目前统一采用EventBus来做处理,在总结学习EventBus之前,觉得还是需要学习总结一下最初的实现方式,也算是不 ...

  3. Android中的Handler,Looper,Message机制

    Android的消息处理有三个核心类:Looper,Handler和Message.其实还有一个Message Queue(消息队列),但是MQ被封装到Looper里面了,我们不会直接与MQ打交道,因 ...

  4. Android中的Handler的机制与用法详解

    概述: 很多android初学者对android 中的handler不是很明白,其实Google参考了Windows的消息处理机制, 在Android系统中实现了一套类似的消息处理机制.在下面介绍ha ...

  5. 转:Android中的Handler的机制与用法详解

    注:Message类的用法: message的几个参数都可以携带数据,其中arg1与arg2可以携带int类型,what是用户自定义的int型,这样接受者可以了解这个消息的信息. 说明:使用Messa ...

  6. Android艺术——探究Handler运行机制

    我们从开发的角度来说,Handler是Android 的消息机制的上层接口.说到Handler,大家都会说:哦,Handler这个我知道干什么的,更新UI.没错,Handler的确是用于更新UI的,具 ...

  7. Android学习之Handler消息传递机制

    Android只允许UI线程修改Activity里的UI组件.当Android程序第一次启动时,Android会同时启动一条主线程(Main Thread),主线程主要负责处理与UI相关的事件,如用户 ...

  8. android学习11——Handler,Looper,MessageQueue工作原理

    Message是Handler接收和处理的消息对象. 每个线程只能拥有一个Looper.它的loop方法读取MessageQueue中的消息,读到消息之后就把消息交给发送该消息的Handler进行处理 ...

  9. Android native进程间通信实例-socket本地通信篇之——基本通信功能

    导读: 网上看了很多篇有关socket本地通信的示例,很多都是调通服务端和客户端通信功能后就没有下文了,不太实用,真正开发中遇到的问题以及程序稳定性部分没有涉及,代码健壮性不够,本系列(socket本 ...

随机推荐

  1. BERT生成能力改进:分离对话生成和对话理解

    NLP论文解读 原创•作者 | 吴雪梦Shinemon 研究方向 | 计算机视觉 导读说明: NLP任务大致可以分为NLU(自然语言理解)和NLG(自然语言生成)两种,NLU负责根据上下文去理解当前用 ...

  2. 二叉搜索树判定方法(c++实现)

    !!版权声明:本文为博主原创文章,版权归原文作者和博客园共有,谢绝任何形式的 转载!! 作者:mohist --- 欢迎指正--- 自己想到的方法是:使用 中序遍历数组或者链表,然后比较数组或者链表中 ...

  3. 【LeetCode】747. Largest Number At Least Twice of Others 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 寻找两次最大值 排序 大顶堆 日期 题目地址:htt ...

  4. 【LeetCode】518. Coin Change 2 解题报告(Python)

    [LeetCode]518. Coin Change 2 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目 ...

  5. 【LeetCode】11. Container With Most Water 盛最多水的容器

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 个人公众号:负雪明烛 本文关键词:盛水,容器,题解,leetcode, 力扣,python ...

  6. Robin Hood

    Robin Hood 题目链接 题意 给你n个人和他们的钱数,然后给你k天,每天可以从最高钱数的人那边取一块钱给最少钱数的人,问最后钱数最多的人和钱数最少的人相差多少: 思路 二分最钱数,能下降到的位 ...

  7. window11连接局域网共享失败处理办法

    第一步1.按 Win + R 组合键,打开运行,并输入:gpedit.msc 命令,确定或回车,可以快速打开本地组策略编辑器2.本地组策略编辑器窗口中,依次展开到:计算机配置 - 管理模板 - 网络 ...

  8. mybatis查询时使用基本数据类型接收报错-attempted to return null from a method with a primitive return type (int)

    一.问题由来 自己在查看日志时发现日志中打印了一行错误信息为: 组装已经放养的宠物数据异常--->Mapper method 'applets.user.mapper.xxxMapper.xxx ...

  9. MCMC using Hamiltonian dynamics

    目录 算法 符号说明 Hamilton方程 物理解释 一些性质 可逆 Reversibility H的不变性 保体积 Volume preservation 辛 Symplecticness 离散化H ...

  10. JavaScript交互式网页设计 • 【第4章 JavaScript文档对象模型】

    全部章节   >>>> 本章目录 4.1 文档对象模型简介及属性 4.1.1 文档对象模型概述 4.1.3 实践练习 4.2 document 对象查找 HTML 元素 4.2 ...