⌈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. ubuntu用户、用户组设置命令总结

    1.ubuntu创建新用户: sudo adduser username(新建一个用户username) 2.设置用户 username 的密码(设置用户username密码) sudo passwd ...

  2. 【九度OJ】题目1054:字符串内排序 解题报告

    [九度OJ]题目1054:字符串内排序 解题报告 标签(空格分隔): 九度OJ [LeetCode] http://ac.jobdu.com/problem.php?pid=1054 题目描述: 输入 ...

  3. 【剑指Offer】05. 替换空格 解题报告 (Python & C++ & Java)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 个人微信公众号:负雪明烛 目录 题目描述 解题方法 方法一:新建可变长度的容器 方法二:原 ...

  4. 「算法笔记」BSGS 与 exBSGS

    一.离散对数 给定 \(a,b,m\),存在一个 \(x\),使得 \(\displaystyle a^x\equiv b\pmod m\) 则称 \(x\) 为 \(b\) 在模 \(m\) 意义下 ...

  5. DEEP DOUBLE DESCENT: WHERE BIGGER MODELS AND MORE DATA HURT

    目录 概 主要内容 Effective Model Complexity(EMC) label noise data augmentation 下降方式 SGD vs Adam Adam SGD SG ...

  6. MCMC using Hamiltonian dynamics

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

  7. CS5262设计DP转HDMI 4K60HZ +VGA 1080P方案芯片

    CS5262是一款带嵌入式MCU的4通道DisplayPort1.4到HDMI2.0/VGA转换器芯片,设计用于将DP1.4信号源连接到HDMI2.0接收器.CS5262集成了DP1.4兼容接收机和H ...

  8. CS5265完美替代CH7211|Type-C转HDMI2.0单转方案|CH7211替代方案

    龙迅Chrontel的CH7211是一款Type-C转HDMI2.0半导体设备,可通过USB Type-C连接器将DisplayPort信号转换为HDMI/DVI.这款创新的基于USB Type-C的 ...

  9. 使用 jQuery 选择器获取页面元素后,利用 jQuery 对象的 css() 方法设置其样式。

    查看本章节 查看作业目录 需求说明: 使用 jQuery 选择器获取页面元素后,利用 jQuery 对象的 css() 方法设置其样式. 要求如下: 点击页面的"更改样式"按钮后, ...

  10. LDAP理解要点

    1.介绍 LDAP(Lightweight Directory Access Protocol)是"轻量级目录访问协议", 是一个用于访问"目录服务器"(Dir ...