首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在UI线程中完成工作时缺少触摸事件

在UI线程中完成工作时缺少触摸事件
EN

Stack Overflow用户
提问于 2019-05-21 23:44:00
回答 2查看 146关注 0票数 0

我正在开发一个Android键盘,它基本上是一个带有LinearLayouts (表示行)的自定义LinearLayout (名为KeyboardView),它有一组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.sleep(为了模拟正在做的大量工作)。这似乎以某种方式重现了这个问题,因为很明显,并不是所有的触摸事件都被接收到。似乎系统具有某种队列,以便接收一些事件,但忽略一些事件。例如,我做了一个简单的键盘,只有ABCD键,睡眠时间为2秒。当一个接一个地按下它们时,仅接收ABD的触摸事件(ACTION_DOWNACTION_MOVEACTION_UP)。但是,在某些情况下会接收到ACTION_CANCEL

为了夸大这个问题,我尝试将睡眠设置为5秒,并在第一次按键睡眠期间单击第二个键。在这种情况下,不会接收到第二次点击的事件,但会接收到第一个按键的所有触摸事件。

对于上述场景,三个接收到的事件如下所示(当输出到日志时)。请注意,第二次按键点击(从未收到)位于log #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

EN

回答 2

Stack Overflow用户

发布于 2019-05-21 23:58:24

触摸事件可以组合在一起,尤其是移动事件。你在检查这个吗?

触摸事件被完全跳过的可能性为0,框架不会这样做。如果是同一类型,合并就会发生。此外,如果你得到一个取消,这意味着触摸事件将转移到另一个视图,在所有手指都被抬起之前,你不会再收到任何触摸事件-因此,如果你看到取消,你应该找出谁偷走了你的触摸。onInterceptTouchEvent不会解决这个问题,因为这只会影响你的孩子,而不会影响到你。如果有什么不同的话,那就是让事情变得更糟。

另外,检查ACTION_POINTER_DOWN和ACTION_POINTER_UP。如果多个手指同时触摸,则会发生这些情况,而不是向上和向下。您可能意外地导致了这些(或者屏幕可能记录错误,特别是当您几乎触摸时,有时可能会有杂散电容)。

票数 0
EN

Stack Overflow用户

发布于 2019-06-11 23:18:12

我终于发现,当我像这样设置它时,一些事件被忽略了。当添加5秒的睡眠时,系统会输出以下内容(后跟使用CPU的列表):

2019-06-11 17:06:45.200 905-990/? E/ActivityManager: ANR in [my_app_identifier]
PID: 10365
Reason: Input dispatching timed out (Waiting to send non-key event because the touched window has not finished processing certain input events that were delivered to it over 500.0ms ago.  Wait queue length: 12.  Wait queue head age: 5490.6ms.)
Load: 0.0 / 0.0 / 0.0
CPU usage from 284899ms to 0ms ago (2019-06-11 17:02:00.002 to 2019-06-11 17:06:44.902) with 99% awake:

这就是我认为会导致一些事件不幸被忽略的原因。因此,休眠线程在这种情况下不是有效的测试。

最后,我从Gabe Sechan的回答中得到了启发,因为这是一种逻辑,当用户快速输入时,他们可能会在举起最后一个手指之前用另一个手指触摸。因此,现在我们也支持ACTION_POINTER_DOWNACTION_POINTER_UP,这似乎工作得更好了。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56241909

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档