在Android开发中,事件分发机制是理解和实现触摸、点击等用户交互的核心。本文将深入探讨Android的事件分发机制,从源码的角度分析触摸事件是如何在Android系统中传递与处理的。
事件分发概述
Android的事件分发机制涉及到多个组件和过程,主要包括:
- 事件产生:用户通过触摸屏幕或其他输入设备产生事件。
- 事件传递:Android系统将事件传递到应用层。
- 事件处理:应用层对事件进行处理,包括拦截、分发、处理等。
事件传递过程
1. 事件产生
当用户触摸屏幕时,触摸屏控制器(Touch Screen Controller)检测到触摸事件,并通过硬件接口发送到Android系统的输入管理器(Input Manager)。
2. 事件传递到应用层
Android系统的输入管理器将事件传递给Activity Manager(简称AM),AM再将事件传递给当前聚焦的窗口(Window)。
3. 事件处理
窗口接收事件后,通过ViewRootImpl将事件传递给顶级视图(通常是DecorView),然后由DecorView开始事件分发。
触摸事件源码分析
以下是从源码角度分析触摸事件如何在Android系统中传递与处理的步骤:
1. InputManagerService
InputManagerService是Android系统中处理输入事件的入口。以下代码展示了InputManagerService接收到触摸事件并创建MotionEvent对象的过程:
// InputManagerService.java
public void onInputEvent(MotionEvent event) {
final long when = event.getDownTime();
mMotionHandler.sendMessage(MotionHandler.obtainMessage(MotionHandler.MSG_PROCESS_INPUT_EVENT, event));
}
// MotionHandler.java
case MSG_PROCESS_INPUT_EVENT:
final MotionEvent event = (MotionEvent) msg.obj;
processMotionEventLocked(event);
break;
2. WindowManagerService
WindowManagerService负责窗口管理和事件分发。以下代码展示了WindowManagerService处理触摸事件并传递给当前窗口的过程:
// WindowManagerService.java
public void onInputEvent(MotionEvent event) {
final int type = event.getActionMasked();
switch (type) {
case MotionEvent.ACTION_DOWN:
deliverInputEvent(event, null);
break;
}
}
// deliverInputEvent.java
private void deliverInputEvent(MotionEvent event, IWindowManagerClient client) {
InputChannel inputChannel = client == null ? null : client.getManagedInputChannel();
if (inputChannel != null) {
event.setInputChannel(inputChannel);
}
mWindowSession.deliverInputEvent(event);
}
3. ViewRootImpl
ViewRootImpl是窗口和视图之间的桥梁。以下代码展示了ViewRootImpl接收到触摸事件并开始事件分发的过程:
// ViewRootImpl.java
public void dispatchInputEvent(MotionEvent event) {
final int action = event.getAction();
final int viewIndex = mFirstTouchTarget == null ? -1 : mFirstTouchTarget.viewId();
if (action == MotionEvent.ACTION_DOWN || (mNonVirtualViews != null && viewIndex < mNonVirtualViews.size())) {
final int viewId = obtainViewId(event);
final View view = obtainView(event, viewId);
boolean handled = false;
if (view != null) {
if (!view.onInterceptTouchEvent(event)) {
handled = view.dispatchTouchEvent(event);
}
}
if (!handled) {
if (mFirstTouchTarget != null) {
event.setLocation(mFirstTouchTarget.getX(), mFirstTouchTarget.getY());
handled = mFirstTouchTarget.dispatchTouchEvent(event);
} else {
final View root = getRootView();
if (root == null) {
return;
}
handled = root.dispatchTouchEvent(event);
}
}
} else {
event.setLocation(mWindowFrame.left, mWindowFrame.top);
handled = onUnhandledDispatch(event);
}
if (!handled) {
if (mFirstTouchTarget != null) {
event.setLocation(mFirstTouchTarget.getX(), mFirstTouchTarget.getY());
handled = mFirstTouchTarget.dispatchTouchEvent(event);
} else {
final View root = getRootView();
if (root == null) {
return;
}
handled = root.dispatchTouchEvent(event);
}
}
}
4. 视图层次结构
在ViewRootImpl中,触摸事件会沿着视图层次结构逐层传递。以下代码展示了触摸事件在视图层次结构中传递的过程:
// View.java
public boolean dispatchTouchEvent(MotionEvent event) {
boolean handled = false;
if (onInterceptTouchEvent(event)) {
event.setLocation(mLeft, mTop);
handled = onTouchEvent(event);
} else {
final boolean intercepted;
View targetView = findTopViewForAccessibility(event);
if (targetView == null) {
targetView = getHostView();
}
intercepted = targetView.onInterceptTouchEvent(event);
if (intercepted) {
event.setLocation(mLeft, mTop);
handled = targetView.onTouchEvent(event);
} else {
final List<View> targetViews = findTopViewsForAccessibility(event);
if (targetViews.isEmpty()) {
handled = dispatchPopulateAccessibilityEvent(event);
} else {
handled = handleTargetEvent(targetViews, event);
}
}
}
return handled;
}
总结
Android的事件分发机制是理解和实现用户交互的核心。通过以上分析,我们可以了解到触摸事件在Android系统中是如何传递与处理的。在实际开发过程中,我们需要根据应用需求,合理地利用事件分发机制,提升用户体验。
