当前位置: 首页 > news >正文

前端好学还是后端好学宝鸡seo

前端好学还是后端好学,宝鸡seo,网站建设业务员话术,石家庄网站建设平台概述 本文主要描述了Android Input框架中的InputReader的功能,InputReader模块的功能,总结成一句话就是InputReader获取输入设备的事件并将事件进行加工处理,然后传递给QueuedInputListener,最终QueuedInputListener将事件传递给…

概述

本文主要描述了Android Input框架中的InputReader的功能,InputReader模块的功能,总结成一句话就是InputReader获取输入设备的事件并将事件进行加工处理,然后传递给QueuedInputListener,最终QueuedInputListener将事件传递给InputDispatcher模块处理,事件处理的方向就是:

InputReader -> QueuedInputListener -> InputDispatcher

本文涉及的源码路径

frameworks/native/services/inputflinger/EventHub.cpp

frameworks/native/services/inputflinger/EventHub.h

frameworks/native/services/inputflinger/InputReader.cpp

frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

InputReader的初始化

InputReader对象由InputManager创建如下所示:

InputManager::InputManager(const sp<EventHubInterface>& eventHub,const sp<InputReaderPolicyInterface>& readerPolicy,const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {/* 创建事件分发对象 */mDispatcher = new InputDispatcher(dispatcherPolicy);/* 创建事件获取对象 */mReader = new InputReader(eventHub, readerPolicy, mDispatcher);initialize();
}

继续深入InputReader类的构造函数,如下所示:

InputReader::InputReader(const sp<EventHubInterface>& eventHub,const sp<InputReaderPolicyInterface>& policy,const sp<InputListenerInterface>& listener) :......mConfigurationChangesToRefresh(0) {// 初始化事件监听器mQueuedListener = new QueuedInputListener(listener);......
}

Inputreader的构造函数比较简单,在这里我们关注构造函数的第一个参数和第三个参数。

eventHub: 获取事件来源的对象,InputReader通过EventHub获取输入设备上报的事件;

listener: InputReader处理完事件后的传递目的地,后面的章节有描述处理流程;

InputReader的运行

在InputManager的初始化过程中,会创建一个InputReadThread线程,如下所示:

void InputManager::initialize() {/* 创建事件获取线程 */mReaderThread = new InputReaderThread(mReader);......
}

InputManager初始化完成开始运行的时候会调用线程的运行方法,对InputReader来说最终调用InputReader::loopOnce, 如下所示:

void InputReader::loopOnce() {......size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);{ // acquire lock......// 处理获取到的intput事件if (count) {processEventsLocked(mEventBuffer, count);}......} // release lock......// 刷新监听队列,将InputReader的事件处理结果,传递给InputDispatcher处理mQueuedListener->flush();
}

InputReader的事件获取

InputReader在Thread线程中调用EventHub的getEvents方法获取输入事件,如下所示:

 size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

该方法将获取到input事件保存在mEventBuffer中,并返回获取到的事件个数

InputReader的事件处理

InputReader从EventHub获取到输入事件后,调用processEventsLocked方法,该方法的核心代码如下所示:

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {for (const RawEvent* rawEvent = rawEvents; count;) {int32_t type = rawEvent->type;size_t batchSize = 1;if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {int32_t deviceId = rawEvent->deviceId;//统计同一个设备上报的事件数while (batchSize < count) {if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT|| rawEvent[batchSize].deviceId != deviceId) {break;}batchSize += 1;}
#if DEBUG_RAW_EVENTSALOGD("BatchSize: %d Count: %d", batchSize, count);
#endif/*** 处理deviceID设备的上报的事件* @batchSize: 事件个数*/processEventsForDeviceLocked(deviceId, rawEvent, batchSize);} else {// 处理EventHub上报的输入设备增加和删除switch (rawEvent->type) {case EventHubInterface::DEVICE_ADDED:addDeviceLocked(rawEvent->when, rawEvent->deviceId);break;case EventHubInterface::DEVICE_REMOVED:removeDeviceLocked(rawEvent->when, rawEvent->deviceId);break;case EventHubInterface::FINISHED_DEVICE_SCAN:handleConfigurationChangedLocked(rawEvent->when);break;default:ALOG_ASSERT(false); // can't happenbreak;}}count -= batchSize;rawEvent += batchSize;}
}

processEventsLocked:方法主要完成如下的功能:

1、处理系统已经存在的输入设备上报的事件;

2、处理系统输入设备的增加和删除事件;

设备添加和删除

本章节主要描述当系统增加一个输入设备时的InputReader处理流程,对于系统设备的删除和扫描的处理流程与增加处理流程类似,这里不再描述。下面我们从系统增加输入设备的处理流程进行描述。系统增加输入设备调用addDeviceLocked方法,addDeviceLocked的核心代码如下所示:

void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {ssize_t deviceIndex = mDevices.indexOfKey(deviceId);// 设备已经增加进来了,直接返回if (deviceIndex >= 0) {ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId);return;}......// 创建InputDevice设备管理对象// @deviceId: 设备ID// @classes: 输入设备类型InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);device->configure(when, &mConfig, 0);device->reset(when);......mDevices.add(deviceId, device);......
}

addDeviceLocked主要完成如下功能:

a、检测该设备是否已经增加过了,如果是,直接返回;

b、根据输入设备的类型,创建InputDevice设备;

c、将创建的InputDevice设备加入到InputReader设备管理容器中;

接着我们分析createDeviceLocked方法,后续我们主要分析多点触控设备的事件处理,因此我们只保留与多点触控相关的核心实现如下所示:

InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,const InputDeviceIdentifier& identifier, uint32_t classes) {InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),controllerNumber, identifier, classes);......// 多点触控if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {device->addMapper(new MultiTouchInputMapper(device));} else if (classes & INPUT_DEVICE_CLASS_TOUCH) {device->addMapper(new SingleTouchInputMapper(device));}return device;
}

createDeviceLocked方法的核心功能比较简单:

a、创建InputDevice设备;

b、根据输入设备的类型安装对应的事件处理器,Android系统可以处理的输入设备种类很多,对于每一类输入设备Android系统都抽象出了一个事件处理器处理该类设备上报的输入事件,对于多点触控设备来说,就是安装MultiTouchInputMapper事件处理器;

c、返回InputDevice设备;

d、这里没有描述InputMapper的实现机制,它的主要作用就是定义事件处理的接口,比如鼠标设备的处理使用CursorButtonAccumulator类,单点触控类设备使用SingleTouchInputMapper,多点触控设备使用MultiTouchInputMapper等,感兴趣的同学可以阅读Android源码去分析它们之间的关系;

设备上报事件

设备上报的输入事件处理函数是processEventsForDeviceLocked,该方法的核心实现,如下所示:

void InputReader::processEventsForDeviceLocked(int32_t deviceId,const RawEvent* rawEvents, size_t count) {......device->process(rawEvents, count);
}

进一步调用InputDevice中的process方法,实现如下:

void InputDevice::process(const RawEvent* rawEvents, size_t count) {......size_t numMappers = mMappers.size();for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {......} else {for (size_t i = 0; i < numMappers; i++) {InputMapper* mapper = mMappers[i];mapper->process(rawEvent);}}}
}

该方法的核心功能就是遍历每一个事件,调用设备自己注册的事件处理器进行处理,对于多点触控设备来说,调用如下的方法:

void MultiTouchInputMapper::process(const RawEvent* rawEvent) {TouchInputMapper::process(rawEvent);/* 处理多点触控坐标信息 */mMultiTouchMotionAccumulator.process(rawEvent);
}

继续调用TouchInputMapper类中的process进行处理,该方法的核心实现,如下所示:

void TouchInputMapper::process(const RawEvent* rawEvent) {/* 鼠标按键事件处理 */mCursorButtonAccumulator.process(rawEvent);/* 鼠标滚轮事件处理 */mCursorScrollAccumulator.process(rawEvent);/* 触摸按键 */mTouchButtonAccumulator.process(rawEvent);// 当前事件全部上报处理完成,进行事件同步操作if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {sync(rawEvent->when);}
}

事件处理的具体细节,我们不再深入谈论,该方法当事件处理完成后,调用sync进行事件同步,核心如下所示:

void TouchInputMapper::sync(nsecs_t when) {......// Sync touch// 同步触摸坐标syncTouch(when, next);......processRawTouches(false /*timeout*/);
}

该方法会调用syncTouch这个虚拟方法,对于多点触控设备来说,最终调用MultiTouchInputMapper子类实现syncTouch, 这里不再详细展开描述。然后调用processRawTouches开始事件的处理,实现方法如下所示:

void TouchInputMapper::processRawTouches(bool timeout) {......const size_t N = mRawStatesPending.size();size_t count;// 遍历每一个上报的事件for(count = 0; count < N; count++) {const RawState& next = mRawStatesPending[count];......mCurrentRawState.copyFrom(next);if (mCurrentRawState.when < mLastRawState.when) {mCurrentRawState.when = mLastRawState.when;}cookAndDispatch(mCurrentRawState.when);}// 事件处理完成,清空mRawStatesPendingif (count != 0) {mRawStatesPending.removeItemsAt(0, count);}.......
}

接着调用cookAndDispatch方法,核心实现如下所示:

void TouchInputMapper::cookAndDispatch(nsecs_t when) {// Always start with a clean state.mCurrentCookedState.clear();......cookPointerData();......} else {// 触摸屏......if (!mCurrentMotionAborted) {dispatchButtonRelease(when, policyFlags);dispatchHoverExit(when, policyFlags);dispatchTouches(when, policyFlags);dispatchHoverEnterAndMove(when, policyFlags);dispatchButtonPress(when, policyFlags);}......}......
}

该方法中,我们为了叙述的简单,只保留了触摸屏幕相关的处理,cookPointerData方法的实现,这里不详细描述,主要就是处理坐标信息,对于触摸屏幕设备来说,就是调用dispatchTouches方法接着处理,核心实现如下所示:

void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {......if (currentIdBits == lastIdBits) {if (!currentIdBits.isEmpty()) {......// 滑动dispatchMotion(when, policyFlags, mSource,AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,AMOTION_EVENT_EDGE_FLAG_NONE,mCurrentCookedState.cookedPointerData.pointerProperties,mCurrentCookedState.cookedPointerData.pointerCoords,mCurrentCookedState.cookedPointerData.idToIndex,currentIdBits, -1,mOrientedXPrecision, mOrientedYPrecision, mDownTime);}} else {......// Dispatch pointer up events.// 触点抬起while (!upIdBits.isEmpty()) {uint32_t upId = upIdBits.clearFirstMarkedBit();dispatchMotion(when, policyFlags, mSource,AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, 0,mLastCookedState.cookedPointerData.pointerProperties,mLastCookedState.cookedPointerData.pointerCoords,mLastCookedState.cookedPointerData.idToIndex,dispatchedIdBits, upId, mOrientedXPrecision, mOrientedYPrecision, mDownTime);dispatchedIdBits.clearBit(upId);}......if (moveNeeded && !moveIdBits.isEmpty()) {ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value);dispatchMotion(when, policyFlags, mSource,AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, 0,mCurrentCookedState.cookedPointerData.pointerProperties,mCurrentCookedState.cookedPointerData.pointerCoords,mCurrentCookedState.cookedPointerData.idToIndex,dispatchedIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime);}// Dispatch pointer down events using the new pointer locations.// 触点按下while (!downIdBits.isEmpty()) {......dispatchMotion(when, policyFlags, mSource,AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0,mCurrentCookedState.cookedPointerData.pointerProperties,mCurrentCookedState.cookedPointerData.pointerCoords,mCurrentCookedState.cookedPointerData.idToIndex,dispatchedIdBits, downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime);}}
}

该方法中会处理三种触摸动作,滑动,抬起和按下,最终调用dispatchMotion方法进行处理,核心实现如下所示:

void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,......float xPrecision, float yPrecision, nsecs_t downTime) {......// 根据触摸屏幕的坐标事件,初始化NotifyMotionArgs对象NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,action, actionButton, flags, metaState, buttonState, edgeFlags,mViewport.displayId, pointerCount, pointerProperties, pointerCoords,xPrecision, yPrecision, downTime);// 找到InputReader的Listen,在初始时指定,最终指向是QueuedInputListenergetListener()->notifyMotion(&args);
}

该方法的核心,就是构造一个NotifyMotionArgs,然后调用InputReader自己的listen中的方法,最终调用QueuedInputListener中的notifyMotion,核心实现如下:

// 加入到内部mArgsQueue队列中
void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {mArgsQueue.push(new NotifyMotionArgs(*args));
}

该方法的实现非常简单,构造一个NotifyMotionArgs,然后加入mArgsQueue队列中。

TouchInputMapper方法的process处理流程方法,讲述完成,然后我们回到MultiTouchInputMapper,接着调用了mMultiTouchMotionAccumulator中的process方法,这里不再展开叙述。

void MultiTouchInputMapper::process(const RawEvent* rawEvent) {TouchInputMapper::process(rawEvent);/* 处理多点触控坐标信息 */mMultiTouchMotionAccumulator.process(rawEvent);
}

至此,一个输入设备的事件处理流程讲述完成,最后,我们回到InputReader线程执行函数的,如下所示:

void InputReader::loopOnce() {......size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);{ // acquire lockAutoMutex _l(mLock);mReaderIsAliveCondition.broadcast();// 处理获取到的intput事件if (count) {processEventsLocked(mEventBuffer, count);}......} // release lock......// 刷新监听队列,将InputReader的事件处理结果,传递给InputDispatcher处理mQueuedListener->flush();
}

我们可以看到,设备上报的所有输入事件处理完成后,最后调用mQueuedListener的flush方法。这个方法的实现,下一个章节进行描述。

InputReader事件传递

上一个章节,我们描述了InputReader处理输入设备上报事件的处理流程,当InputReader处理完上报的事件后调用mQueuedListener的flush,该方法的实现如下所示:

void QueuedInputListener::flush() {size_t count = mArgsQueue.size();for (size_t i = 0; i < count; i++) {NotifyArgs* args = mArgsQueue[i];args->notify(mInnerListener);delete args;}mArgsQueue.clear();
}

该方法的实现比较简单,调用notify虚拟方法,对于触摸设备来说就是调用子类实现如下所示:

// 直接传递给InputDispatcher
void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {listener->notifyMotion(this);
}

直接调用listener的notifyMotion进行处理,这里的listener其实就是InputDispatcher,这在InputReader初始化的时候进行传递的,如下所示:

InputManager::InputManager(const sp<EventHubInterface>& eventHub,const sp<InputReaderPolicyInterface>& readerPolicy,const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {/* 创建事件分发对象 */mDispatcher = new InputDispatcher(dispatcherPolicy);/* 创建事件获取对象 */mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
}InputReader::InputReader(const sp<EventHubInterface>& eventHub,const sp<InputReaderPolicyInterface>& policy,const sp<InputListenerInterface>& listener) :mContext(this), mEventHub(eventHub), mPolicy(policy),mGlobalMetaState(0), mGeneration(1),mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),mConfigurationChangesToRefresh(0) {// 初始化事件监听器mQueuedListener = new QueuedInputListener(listener);{ // acquire lockAutoMutex _l(mLock);refreshConfigurationLocked(0);updateGlobalMetaStateLocked();} // release lock
}

将InputDispatcher当做QueuedInputListener的listener。最终listener->notifyMotion(this)调用到,如下所示:

void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
......
}

这里不再详解展开描述,在InputDispatcher模块进行详细描述。

总结

本文描述了InputReader对EventHub事件的处理,InputReader对于每一个不同类型的输入设备调用对应的事件处理器进行处理,当事件处理完成后最终将处理结果传递给InputDispatcher。下一章我们描述InputDispatcher的功能。

http://www.cadmedia.cn/news/4785.html

相关文章:

  • 网站建设 提供源码芭蕉视频app无限次数
  • 学做日料的网站网站ip查询
  • 广州网站建设公网站关键词查询网址
  • 百度搜索网百度快速收录seo工具软件
  • 深圳网站建设定制开发超凡科技seo网站优化服务合同
  • 网站排名优化外包沈阳沈河seo网站排名优化
  • 高校思想政治理论课程网站建设团队制作网站的软件
  • 做个医院网站多少钱建站企业网站
  • 模板网站 seo公众号推广引流
  • 网站域名注册流程全球最受欢迎的网站排名
  • 网站建设与运营 好考吗电商网站seo
  • 网站建设需要哪些成本费用360推广开户
  • 女装网站建设规划书怎么写视频号最新动作
  • 手机网站建设目标北京网站优化步
  • 中国包装创意设计大赛郑州网站建设优化
  • 湛江网站制作多少钱软件推广方案经典范文
  • 合肥网站建设技术托管怎样把产品放到网上销售
  • 桂林两江四湖夜景图片关键词优化的发展趋势
  • 网站开发 教程中国企业500强最新排名
  • 安平网站建设培训google官网
  • 河北省建设厅注册中心网站石家庄seo网络优化的公司
  • 网站建设付款分期付款协议简述什么是网络营销
  • 安阳那里可以制作网站怎样把个人介绍放到百度
  • 江西网站设计方案百度公司图片
  • 网站推广seo设置十大经典事件营销案例分析
  • 鄂州市城乡建设委员会网站临沂网站seo
  • 西宁专业企业网站建设萝卜建站
  • 汕头招聘网官网登录seo做什么网站赚钱
  • 优秀的网络营销策划书衡阳seo优化首选
  • 品牌建设的最高境界是培育客户成为seo软件优化工具软件