1.引言
看《android源码设计模式》讲命令模式那章,介绍了下Input机制。让我联想起同事给我那篇关于Input事件机制的文档。于是决定自己琢磨琢磨,了解了解,Input机制的知识。
参考:
https://www.jianshu.com/p/faedef1910fe
https://www.jianshu.com/p/f05d6b05ba17
http://gityuan.com/2016/12/10/input-manager/
2.正题
2.1基本知识和概念
EventHub
:
EventHub,它主要是利用Linux的inotify和epoll机制,监听设备事件:包括设备插拔及各种触摸、按钮事件等,可以看做是一个不同设备的集线器,主要面向的是/dev/input目录下的设备节点,比如说/dev/input/event0上的事件就是输入事件,通过EventHub的getEvents就可以监听并获取该事件。
InputReader:
EventHub得到RowEvent之后,交给InputReader进行加工成我们需要的KeyEvent。并将Event传递给InputDispatcher,
InputDispatcher:
InputDispatcher负责将event传递给,Window。一个手机又多个Window,传递给哪个Window就是InputDispatcher 做的事。
2.2 如何将事件分发给上层应用
- InputChannel: 底层和上层通信的核心(非binder通信而是Socket通信)。openInputChannelPair方法中文翻译就是创建,一对input通道,应用层持有一个channel,InputDispatcher持有另外一个。这样形成c/s端。应用层作为Server,InputDispatcher作为Client.进而传递Event
/**
* Creates a new input channel pair. One channel should be provided to the input
* dispatcher and the other to the application's input queue.
* @param name The descriptive (non-unique) name of the channel pair.
* @return A pair of input channels. The first channel is designated as the
* server channel and should be used to publish input events. The second channel
* is designated as the client channel and should be used to consume input events.
*/
public static InputChannel[] openInputChannelPair(String name) {
if (name == null) {
throw new IllegalArgumentException("name must not be null");
}
if (DEBUG) {
Slog.d(TAG, "Opening input channel pair '" + name + "'");
}
return nativeOpenInputChannelPair(name);
}
- WindowInputEventReceiver:上层接受事件的入口。
原英文解释:Provides a low-level mechanism for an application to receive input events
ViewRootImp#setView
1.创建Channel
2.将Channel传递给WMS
3.创建WindowInputEventReceiver
4.创建InputStage 责任链设计模式
上图并不是包装者模式,而是地地道道的责任链模式。构造方法中指定的对象作为是为Next赋值的。
最终执行到 ViewPostImeInputStage#processPointerEvent。进而走了DecorView#dispatchPointerEvent方法。
DecorView#dispatchPointerEvent最终会调用到
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final Window.Callback cb = mWindow.getCallback();
return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}
其中WindowCallBack.被Activity实现。所以会走进Activity#dispatchTouchEvent。
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
activity的getWindow() 就是我们的PhoneWindow。而PhoneWindow又是调用的。DecorView# dispatchTouchEvent方法 进入了 我们熟悉的事件传递过程。
ps技巧:Log.getStackTraceString(new Throwable()) 打印堆栈,帮我们分析函数调用过程
网友评论