从之前小节我们知道Dispatcher线程是如何分发事件给APP的,该小节我们讲解APP如何获取,并且处理这些输入事件。在前面的小节中,提到APP在得到一个fd之后,会把他封装成一个InputChannel,然后再封装成windowInputEvenReceiver,最终把fd注册到Looper中,使用epoll进行查询等待,该小节我们详细的分析fd注册到Looper的过程,APP调用总的详细框图如下:
在应用程序中,对于文件句柄fd,InputChannel的注册是从框图中ViewRootImpl.java文件,的setView方法中的WindowInputEventReceiver开始,其ViewRootImpl.java文件的调用过程如下:
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
/*从调用.addToDisplay方法获取mInputChannel*/
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,mAttachInfo.mOutsets, mInputChannel);
/*注册fd,或者说InputChannel,因为fd被包含在InputChannel中*/
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,Looper.myLooper();
现在我们从WindowInputEventReceiver(mInputChannel,Looper.myLooper()开始分析,先查看 WindowInputEventReceiver这个类包含了什么
final class WindowInputEventReceiver extends InputEventReceiver {
public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
}
@Override
public void onInputEvent(InputEvent event) {
enqueueInputEvent(event, this, 0, true);
}
@Override
public void onBatchedInputEventPending() {
if (mUnbufferedInputDispatch) {
super.onBatchedInputEventPending();
} else {
scheduleConsumeBatchedInput();
}
}
@Override
public void dispose() {
unscheduleConsumeBatchedInput();
super.dispose();
}
}
从上面我们可以看到,WindowInputEventReceiver继承于InputEventReceiver,然后重写了onInputEvent(InputEvent event),onBatchedInputEventPending(),dispose()三个方法。当接收到事件的时候,onInputEvent方法会被调用。
既然WindowInputEventReceiver继承于InputEventReceiver,那么当创建WindowInputEventReceiver实例化对象的时候,InputEventReceiver的构造方法肯定会被调用。我们可以看到InputEventReceiver中包含如下函数:
private void dispatchInputEvent(int seq, InputEvent event) {
onInputEvent(event);
从上分析,子类WindowInputEventReceiver中的onInputEvent方法,应该是被父类InputEventReceiver的dispatchInputEvent方法调用的,
再来看看InputEventReceiver的构造函数,
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
mReceiverPtr = nativeInit(new WeakReference(this),inputChannel, mMessageQueue);
该处的nativeInit会调用android_view_InputEventReceiver.cpp中的:
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,jobject inputChannelObj, jobject messageQueueObj) {
sp receiver = new NativeInputEventReceiver(env,receiverWeak, inputChannel, messageQueue);
这样就从java到cpp文件了,在android_view_InputEventReceiver.cpp文件中,存在函数:
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
/*最终调用java中的dispatchInputEvent方法*/
env->CallVoidMethod(receiverObj.get(),gInputEventReceiverClassInfo.dispatchBatchedInputEventPending);
我们再次回到android_view_InputEventReceiver.cpp的 nativeInit函数:
static jlong nativeInit(JNIEnv* env, jclass clazz, jobjectreceiverWeak,jobject inputChannelObj, jobject messageQueueObj) {
/*获取一个NativeInputEventReceiver类型的实例化对象*/
sp receiver = new NativeInputEventReceiver(env,receiverWeak, inputChannel, messageQueue);
/*通过其实例化对象,调用initialize()函数*/
status_t status = receiver->initialize();
/*该处就是把InputChannel的fd注册到Looper*/
setFdEvents(ALOOPER_EVENT_INPUT);
/*InputChannel从获取fd*/
int fd = mInputConsumer.getChannel()->getFd();
/*添加到Looper,注意该处的第3个参数是this,表示当前这个实例化对象,即
receiver = new NativeInputEventReceiver(env,receiverWeak, inputChannel, messageQueue); */
mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
现在我们打开SDK/system/core/libutils/looper.cpp文件,在其类可以找打两个Looper::addFd函数:
int Looper::addFd(int fd, int ident, int events, Looper_callbackFunc callback, void* data) {
int Looper::addFd(int fd, int ident, int events, const sp& callback, void* data) {
根据两个函数倒数第二个参数,前面的为一个函数指针,第二个为一个实LooperCallback例化对象,但是我们之前通过receiver = new NativeInputEventReceiver(env,receiverWeak, inputChannel, messageQueue)并非LooperCallback例化对象,那么可以猜测到NativeInputEventReceiver为LooperCallback的一个派生类。
在android_view_InputEventReceiver.cpp可以看到如下:
class NativeInputEventReceiver : public LooperCallback {
这样就证明了我们的猜测,那么他调用的就是第二个int Looper::addFd,
int Looper::addFd(int fd, int ident, int events, const sp& callback, void* data) {
/*构建一个Reques*/
Request request;
request.fd = fd;
/*调用该函数,添加到epoll_ctl之中*/
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
这样,就可以使用epoll,对输入事件进行监测了。 我们来看看LooperCallback包含呢那些东西:
virtual int handleEvent(int fd, int events, void* data) = 0
该 handleEvent会调用派生类中的consumeEvents,这样注册部分就讲解完成,下面我们来看看APP获取事件的流程。
获取事件再次打开Looper.cpp,在其了存在:
int Looper::pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
result = pollOnce(timeoutMillis, outFd, outEvents, outData);
result = pollInner(timeoutMillis);
/*等待fd动作*/
eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
/*根据返回结果,取出若干个事件*/
for (int i = 0; i CallVoidMethod(receiverObj.get(),gInputEventReceiverClassInfo.dispatchBatchedInputEventPending);
然后在InputEventReceiver.java中的dispatchInputEvent:
private void dispatchInputEvent(int seq, InputEvent event) {
/*该具体方法,为派生类实现的*/
onInputEvent(event);
现在我们来查看ViewRootImpl.java中实现的onInputEvent:
public void onInputEvent(InputEvent event) {
enqueueInputEvent(event, this, 0, true);//放入队列
void enqueueInputEvent(InputEvent event,InputEventReceiver receiver, int flags, boolean processImmediately) {
doProcessInputEvents();//处理众多的事件
deliverInputEvent(q);//传输事件
/*把事件分为多个阶段*/
InputStage stage;
其上事件的阶段处理详细阶梯图如下: 现在我们对这个阶梯图进行讲解,在最开始提到WindowInputEventReceiver是java层面对输入事件处理的总入口,他会调用onInputEvent,在根据之前分析从onInputEvent到deliverInputEvent,deliverInputEvent会把输入事件分为多个阶段,
1.NativePrelme与ViewPrelme为输入法之前,对输入事件的处理。 2.lme对输入法的处理 3.EarlyPostime到viewPostime为输入法之后做的处理 4.Synthetic为对事件综合的处理 如果你的应用程序不使用输入法,他会从3开始处理,如果使用输入法,从1开始处理。
应用程序可能是C++编写,也可能是java编写, c++:使用Native Activity处理 java:使用View-onKeyDown()处理
在框图右边的部分,都处于一个链表,我们看看这个链表是如何创建出来的: 在ViewRootImpl.java可以找:
CharSequence counterSuffix = attrs.getTitle();
mSyntheticInputStage = new SyntheticInputStage();
InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
"aq:native-post-ime:" + counterSuffix);
InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
InputStage imeStage = new ImeInputStage(earlyPostImeStage,
"aq:ime:" + counterSuffix);
InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
"aq:native-pre-ime:" + counterSuffix);
该处我们可以看待先创建Synthetic,然后他当做参数传入ViewPostImeInputStage…依此递推,就创建一个链表出来。
知道链表怎么创建之后,我们再回到deliverInputEvent:
private void deliverInputEvent(QueuedInputEvent q) {
if (q.shouldSendToSynthesizer()) {
/*判断是否能够忽略输入法,从图示对应位置开始执行*/
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
stage.deliver(q);//为public final void deliver(QueuedInputEvent q) {
/*如果当前阶段结束*/
if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
forward(q);//传递给下一个阶段
} else if (shouldDropInputEvent(q)) {//判断该事件能否丢弃
finish(q, false);//设置标志位
else {
apply(q, onProcess(q));//没有结束,也不能抛弃,这执行该函数
}
从上可知,每个阶段进行处理的时候,只有3个结果 1.如果已经完成,进入下一阶段 2.设置标志位为finish,传递给下一阶段 3.调用onProcess函数处理,处理完成传递给下一个stage
下一小节再继续详细分析