您的位置:首页 > 移动开发 > Android开发

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

2015-07-19 11:25 603 查看
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)) {
...
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: