【发布时间】:2019-05-21 15:44:00
【问题描述】:
我正在开发一个 Android 键盘,它基本上是一个自定义的 LinearLayout(命名为 KeyboardView)和 LinearLayouts(代表行),它有一组 TextViews(代表键)。如果它应该用 XML 表示,它会是这样的:
<KeyboardView> <!-- extends LinearLayout -->
<LinearLayout> <!-- row #1 -->
<TextView /> <!-- key #1 -->
... <!-- more TextViews -->
</LinearLayout>
... <!-- more rows/LinearLayouts -->
</KeyboardView>
在KeyboardView 中,我覆盖onTouchEvent,并且如果用户在TextViews 之一的范围内触摸,则调用控制器(并且该控制器确定应如何处理键)。这意味着KeyboardView 的孩子永远不会获得焦点事件。出于各种原因以这种方式完成,例如因此可以处理在键盘上的滑动。
这在大多数情况下都可以正常工作,但我们收到了一些关于键盘并不总是对所有触摸事件做出反应的报告。可能很难重现这种行为,但我们已经确认它不是由用户触摸按键之间的间隙引起的(因为没有间隙),所以我们认为在某些情况下我们需要花费太多时间来弄清楚应该用密钥做什么 - onTouchEvent 的执行时间可能太长了。
为了验证这个理论,我最终在onTouchEvent 中添加了一些Thread.sleeps(以模拟正在完成的大量工作)。这似乎以某种方式重现了这个问题,因为很明显不是所有的触摸事件都被接收到。似乎系统有某种队列,以便接收一些事件,但忽略一些事件。我例如制作了一个简单的键盘,只有 A、B、C 和 D 键,睡眠时间为 2 秒。当一个接一个地按下它们时,只会收到A、B 和 D 的触摸事件(ACTION_DOWN、ACTION_MOVE、ACTION_UP)。但是在某些情况下会收到ACTION_CANCEL。
为了夸大问题,我尝试将睡眠设置为5秒,并在第一次按键触摸的睡眠期间单击第二个按键。在这种情况下,不会收到第二次点击的任何事件 - 但会收到第一次按键的所有触摸事件。
对于上述场景,三个接收到的事件如下(输出到日志时)。请注意,第二次按键点击(从未收到)在日志 #1 和 #2 之间:
MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=181.0, y[0]=536.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=116942926, downTime=116942926, deviceId=8, source=0x1002 }
MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=181.0, y[0]=536.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=2, eventTime=116942992, downTime=116942926, deviceId=8, source=0x1002 }
MotionEvent { action=ACTION_UP, actionButton=0, id[0]=0, x[0]=181.0, y[0]=536.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=116942999, downTime=116942926, deviceId=8, source=0x1002 }
我不知道它只是 Android 框架的一部分还是我遗漏了一些东西。我可以“只是”将完成的工作 onTouchEvent 放到一个线程中,但我担心它只是涵盖了真正的问题,而且我通常更愿意尽可能避免使用线程。我也尝试过覆盖onInterceptTouchEvent 并始终让它返回true(以尽量避免ACTION_CANCEL),但在某些情况下仍然会出现ACTION_CANCEL。
【问题讨论】:
标签: android event-handling touch-event motionevent