Android Native Looper机制 - 监听文件描述符

Navite Looper 除了提供message机制之外,还提供了监听文件描述符的方式。
通过addFd()接口加入需要被监听的文件描述符。

    int addFd(int fd, int ident, int events, Looper_callbackFunc callback, void* data);
    int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data);  

其中:
- fd:为所需要监听的文件描述符。
- ident:表示为当前发生事件的标识符,必须>=0,或者为POLL_CALLBACK(-2)如果指定了callback。
- events:表示为要监听的文件类型,默认是EVENT_INPUT。
- callback:当有事件发生时,会回调该callback函数。
- data: 两种使用方式:
指定callback来处理事件 : 当该文件描述符上有事件到来时,该callback会被执行,然后从该fd读取数据。这个时候ident是被忽略的。
通过指定的ident来处理事件: 当该文件描述符有数据到来时,pollOnce() 会返回一个ident,调用者会判断该ident是否等于自己需要处理的事件ident,如果是的话,则开始处理事件。

1. 通过指定的ident来处理事件:

使用场景:

Android 4.0.4版本SensorEventQueue.cpp 有使用。
SensorEventQueue.cpp : getLooper() : 将所需奥监听的文件描述符增加到looper中。

sp<Looper> SensorEventQueue::getLooper() const
{
    Mutex::Autolock _l(mLock);
    if (mLooper == 0) {
        mLooper = new Looper(true);
        // 将要监听的文件描述符作为事件的标识符穿进去,并且callback为null
        mLooper->addFd(getFd(), getFd(), ALOOPER_EVENT_INPUT, NULL, NULL);
    }
    return mLooper;
}  

SensorEventQueue.cpp : waitForEvent(): 通过looper的pollOnce轮询监听事件,然后返回事件的标识符,如果事件的标识符等于getFd()所监听的文件描述符时,则返回NO_ERROR。

status_t SensorEventQueue::waitForEvent() const
{
    const int fd = getFd();
    sp<Looper> looper(getLooper());

    int events;
    int32_t result;
    do {
        result = looper->pollOnce(-1, NULL, &events, NULL);
        if (result == ALOOPER_POLL_ERROR) {
            ALOGE("SensorEventQueue::waitForEvent error (errno=%d)", errno);
            result = -EPIPE; // unknown error, so we make up one
            break;
        }
        if (events & ALOOPER_EVENT_HANGUP) {
            // the other-side has died
            ALOGE("SensorEventQueue::waitForEvent error HANGUP");
            result = -EPIPE; // unknown error, so we make up one
            break;
        }
    } while (result != fd);

    return  (result == fd) ? status_t(NO_ERROR) : result;
}

android/4.0.4/frameworks/base/core/jni/android_hardware_SensorManager.cpp : sensor_data_poll()
早期版本采用如下的消息驱动机制,在5.0版本已经没有这样使用了。
可以看到:当waitForEvent() 返回NO_ERROR,就会去读取数据。

static jint
sensors_data_poll(JNIEnv *env, jclass clazz, jint nativeQueue,
        jfloatArray values, jintArray status, jlongArray timestamp)
{
    sp<SensorEventQueue> queue(reinterpret_cast<SensorEventQueue *>(nativeQueue));
    if (queue == 0) return -1;

    status_t res;
    ASensorEvent event;

    res = queue->read(&event, 1);
    if (res == -EAGAIN) {
        res = queue->waitForEvent();
        if (res != NO_ERROR)
            return -1;
        res = queue->read(&event, 1);
    }
    if (res < 0)
        return -1;

    jint accuracy = event.vector.status;
    env->SetFloatArrayRegion(values, 0, 3, event.vector.v);
    env->SetIntArrayRegion(status, 0, 1, &accuracy);
    env->SetLongArrayRegion(timestamp, 0, 1, &event.timestamp);

    return event.sensor;
}

2. 指定callback来处理事件:

callback 必须是继承子LooperCallback,或者是如下形式的回调函数。
typedef int (*Looper_callbackFunc)(int fd, int events, void* data);

实际上这种形式也是封装成了SimpleLooperCallback对象,该对象同样是继承自LooperCallback。

int Looper::addFd(int fd, int ident, int events, Looper_callbackFunc callback, void* data) {
    return addFd(fd, ident, events, callback ? new SimpleLooperCallback(callback) : NULL, data);
}

SimpleLooperCallback定义如下,在Looper.h 文件

/**
 * Wraps a Looper_callbackFunc function pointer.
 */
class SimpleLooperCallback : public LooperCallback {
protected:
    virtual ~SimpleLooperCallback();

public:
    SimpleLooperCallback(Looper_callbackFunc callback);
    virtual int handleEvent(int fd, int events, void* data);

private:
    Looper_callbackFunc mCallback;
};
使用场景1:
InputDispatcher.cpp : registerInputChannel() 
 mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);

handleReceiveCallback() 的实现如下:
int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {
    InputDispatcher* d = static_cast<InputDispatcher*>(data);
...
使用场景2:

android_view_InputEventReceiver.cpp : setFdEvents() 将fd加入looper 轮询监听,另外还需要实现一个handleEvent() 函数。

void NativeInputEventReceiver::setFdEvents(int events) {
    if (mFdEvents != events) {
        mFdEvents = events;
        int fd = mInputConsumer.getChannel()->getFd();
        if (events) {
            mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
        } else {
            mMessageQueue->getLooper()->removeFd(fd);
        }
    }
}

int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
    if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
...
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 中的 Looper 机制是一个消息循环系统,用于管理应用程序中的消息队列。在 Python 中,我们可以使用 `queue` 模块来实现类似的机制。以下是一个使用 `queue` 模块实现的死循环示例: ```python import queue def my_handler(): while True: try: message = my_queue.get(block=True, timeout=1) except queue.Empty: continue # 处理消息 print(f"Received message: {message}") # 将消息放回队列 my_queue.put(message) # 创建消息队列 my_queue = queue.Queue() # 启动消息处理循环 my_handler() ``` 在这个示例中,我们定义了一个 `my_handler()` 函数,它包含一个无限循环,它会从一个队列中获取消息,并对消息进行处理。如果队列为空,循环将等待 1 秒钟,然后重试。在处理完消息后,循环将消息放回队列中,以便其他线程可以处理它。 要使用这个循环,我们需要创建一个队列,并将消息放入队列中。例如: ```python # 将两条消息放入队列中 my_queue.put("Hello") my_queue.put("World") # 等待一段时间 time.sleep(5) # 取出队列中的消息 while not my_queue.empty(): message = my_queue.get() print(f"Got message: {message}") ``` 在这个示例中,我们创建了一个队列,并将两条消息放入队列中。然后,我们等待 5 秒钟,并从队列中取出所有的消息并打印它们。在此过程中,`my_handler()` 函数将一直运行,并处理队列中的消息,直到程序结束。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值