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

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

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


前言

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

代码

直接上代码,如下

//
// Copyright 2010 The Android Open Source Project
//
//#define LOG_NDEBUG 0
#define LOG_TAG "LooperTest" #include <utils/Looper.h>
#include <utils/Timers.h>
#include <utils/Log.h>
#include <unistd.h>
#include <time.h>
#include <utils/threads.h> // # of milliseconds to fudge stopwatch measurements
#define TIMING_TOLERANCE_MS 25 using namespace android;
using namespace std; class StubMessageHandler : public MessageHandler {
public:
Vector<Message> messages; virtual void handleMessage(const Message& message) {
ALOGD("[Thread=%d] %s message.what=%d \n", gettid(), __func__, message.what);
messages.push(message);
}
}; struct LooperThread : public Thread {
public:
LooperThread(Looper *looper)
: mLooper(looper) {
} virtual bool threadLoop() {
if(mLooper == NULL)
return false;
int32_t ret = mLooper->pollOnce(-1);
switch (ret) {
case Looper::POLL_WAKE:
case Looper::POLL_CALLBACK:
return true;
case Looper::POLL_ERROR:
ALOGE("Looper::POLL_ERROR");
return true;
case Looper::POLL_TIMEOUT:
// timeout (should not happen)
return true;
default:
// should not happen
ALOGE("Looper::pollOnce() returned unknown status %d", ret);
return true;
}
} protected:
virtual ~LooperThread() {} private:
Looper *mLooper;
}; class CallbackHandler {
public:
CallbackHandler() : callbackCount(0) {}
void setCallback(const sp<Looper>& looper, int fd, int events) {
looper->addFd(fd, 0, events, staticHandler, this);
} protected:
int handler(int fd, int events) {
callbackCount++;
ALOGD("[Thread=%d] %s fd=%d, events=%d, callbackCount=%d\n", gettid(), __func__, fd, events, callbackCount);
return 0;
} private:
static int staticHandler(int fd, int events, void* data) {
return static_cast<CallbackHandler*>(data)->handler(fd, events);
}
int callbackCount;
}; class Pipe {
public:
int sendFd;
int receiveFd; Pipe() {
int fds[2];
::pipe(fds); receiveFd = fds[0];
sendFd = fds[1];
} ~Pipe() {
if (sendFd != -1) {
::close(sendFd);
} if (receiveFd != -1) {
::close(receiveFd);
}
} status_t writeSignal() {
ssize_t nWritten = ::write(sendFd, "*", 1);
return nWritten == 1 ? 0 : -errno;
} status_t readSignal() {
char buf[1];
ssize_t nRead = ::read(receiveFd, buf, 1);
return nRead == 1 ? 0 : nRead == 0 ? -EPIPE : -errno;
}
}; int main(int argc, char ** argv)
{
// Looper的轮询处理工作在新线程中
sp<Looper> mLooper = new Looper(true);
sp<LooperThread> mLooperThread = new LooperThread(mLooper.get());
mLooperThread->run("LooperThread"); // 测试消息的发送与处理
sp<StubMessageHandler> handler = new StubMessageHandler();
ALOGD("[Thread=%d] sendMessage message.what=%d \n", gettid(), 1);
mLooper->sendMessage(handler, Message(1));
ALOGD("[Thread=%d] sendMessage message.what=%d \n", gettid(), 2);
mLooper->sendMessage(handler, Message(2)); sleep(1); // 测试监测fd与回调callback
Pipe pipe;
CallbackHandler mCallbackHandler;
mCallbackHandler.setCallback(mLooper, pipe.receiveFd, Looper::EVENT_INPUT);
ALOGD("[Thread=%d] writeSignal 1\n", gettid());
pipe.writeSignal(); // would cause FD to be considered signalled
sleep(1);
mCallbackHandler.setCallback(mLooper, pipe.receiveFd, Looper::EVENT_INPUT);
ALOGD("[Thread=%d] writeSignal 2\n", gettid());
pipe.writeSignal(); sleep(1);
mLooperThread->requestExit();
mLooper.clear();
}

编译Android.mk,如下

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) LOCAL_SRC_FILES := LooperTest.cpp LOCAL_SHARED_LIBRARIES := \
liblog \
libutils \ LOCAL_C_INCLUDES := \
system/core/include/cutils \ LOCAL_MODULE_TAGS := optional LOCAL_MODULE := LooperTest 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

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

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

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

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

Pipe pipe;
CallbackHandler mCallbackHandler;
mCallbackHandler.setCallback(mLooper, pipe.receiveFd, Looper::EVENT_INPUT);
ALOGD("[Thread=%d] writeSignal 1\n", gettid());
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. c++内存分布之纯虚函数

    关于 本文演示环境:VS2017+32位程序. 纯虚函数是一种特殊的虚函数.可以预测到:虚函数的结论同样适用纯虚函数,但是纯虚函数是一种特殊的存在,还是看看实际结果. 代码写的不够规范: 因为任何带虚 ...

  2. 【LeetCode】268. Missing Number 解题报告(Java & Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 求和 异或 日期 题目地址:https://leet ...

  3. 【LeetCode】31. Next Permutation 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 逆序数字交换再翻转 库函数 日期 题目地址:http ...

  4. 【LeetCode】199. Binary Tree Right Side View 解题报告(Python)

    [LeetCode]199. Binary Tree Right Side View 解题报告(Python) 标签: LeetCode 题目地址:https://leetcode.com/probl ...

  5. 【LeetCode】848. Shifting Letters 解题报告(Python)

    [LeetCode]848. Shifting Letters 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http ...

  6. 【机器学习】matplotlib库练习-函数绘图

    # 1创建2个图形区域,一个叫做green,大小是16,8,一个叫做red,大小是10,6 # 2绿色区域画一条绿色的正弦曲线,红色区域化两条线,一条是绿色的正弦曲线,一条是红色的余弦曲线 # 3在g ...

  7. Glossary Collection

    目录 直接修饰用 间接强调用 (多为副词) 过渡用 特别的名词 动词 词组 各种介词 句子 摘要 引言 总结 正文 实验 直接修饰用 Word 含义 例句 近义词 nuanced adj. 微妙的:具 ...

  8. Java面向对象笔记 • 【第7章 集合】

    全部章节   >>>> 本章目录 7.1 集合概述 7.1.1 Java集合体系概述 7.1.2 实践练习 7.2 List集合 7.2.1 ArrayList实现类 7.2. ...

  9. UI自动化,通过Xpath结合父类、同级元素,查找到唯一的元素定位

    UI自动化,通过Xpath定位的总结 当页面展示的内容的html布局格式一样,只能第几个控件的绝对定位来区分时,如果后面有变更控件的顺序,就会导致找不到这个元素,维护成本较高,可以尝试用其他的方式,比 ...

  10. 关闭SpringBoot logo图标

    public static void main(String[] args) {// SpringApplication.run(LicenseApp.class, args); //关闭Spring ...