SimpleOnGestureListener.onScroll方法接收到null值并崩溃。

7
我正在使用手势检测器来捕获滚动视图的滚动事件:
val gestureDetector = GestureDetector(this.fragment.activity, ScrollGestureListener(scrollView))
scrollView.setOnTouchListener(OnTouchListener { view, event ->
    gestureDetector.onTouchEvent(event)
    return@OnTouchListener false
})

internal inner class ScrollGestureListener(view: View) : GestureDetector.SimpleOnGestureListener() {
    override fun onScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean {
        this@DocumentViewer.onDrag()
        return true
    }
}

当使用compileSdkVersion 30时,我的应用程序会在onScroll函数上崩溃,因为它总是接收到第一个参数的空值。我通过使第一个参数变成可选项来解决这个问题:

override fun onScroll(e1: MotionEvent?, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean {

现在我正在尝试将compileSdkVersion更新到33,那么上面的代码行将不能编译。但是,如果我恢复标准函数签名,那么当我滚动滚动视图时,应用程序会再次崩溃。

这个SO帖子上的评论说:"如果除手势检测器以外的其他东西消耗了ACTION_DOWN事件,你就会遇到这样的崩溃。" 但是我无法弄清楚还有什么东西会这样做。在这个片段的一些其他视图上我有手势检测器,但是如果我注释掉所有这些代码,崩溃仍然存在。

我暂时添加了onDown的实现到我的ScrollGestureListener,但它从未被调用过,所以似乎与ACTION_DOWN有关。

查看GestureDetector.java的源代码,我发现它发送给onScroll的第一个参数是mCurrentDownEvent,所以这也似乎与ACTION_DOWN有关。但是,如果我在Android Studio中为GestureDetector.java添加断点,mCurrentDownEvent从未显示为空。而且,它始终与作为第二个参数传递的事件(ev)相同--GestureDetector只是将mCurrentDownEvent设置为ev的副本。

看起来当GestureDetector调用onScroll时,崩溃发生了,因为我onScroll方法中的断点没有被触发,如果我删除我的onScroll重写,同样的崩溃也会发生 -- 显然只调用超类实现的onScroll就会导致崩溃。以下是控制台中显示的内容:

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.arlomedia.bandhelper, PID: 18797
java.lang.NullPointerException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkNotNullParameter, parameter e1
    at com.arlomedia.bandhelper.helpers.DocumentViewer$ScrollGestureListener.onScroll(Unknown Source:2)
    at android.view.GestureDetector.onTouchEvent(GestureDetector.java:788)
    at com.arlomedia.bandhelper.helpers.DocumentViewer.viewDocument$lambda-9(DocumentViewer.kt:1398)
    at com.arlomedia.bandhelper.helpers.DocumentViewer.$r8$lambda$kyj-4h2jNAIkIYOWSE7_HVetJAg(Unknown Source:0)
    at com.arlomedia.bandhelper.helpers.DocumentViewer$$ExternalSyntheticLambda7.onTouch(Unknown Source:6)
    at android.view.View.dispatchTouchEvent(View.java:15147)

在调用onTouchEvent之前,我尝试在我的OnTouchListener中添加一些检查--类似于这样:

if (event != null) {
    gestureDetector.onTouchEvent(event)
}

但是在这里 event 永远不会为空,在查看其属性时,我没有看到任何可以检查是否会导致崩溃的东西。

另一个潜在的线索是,只有当我的手指在调用 onTouchEvent 时仍然触摸屏幕时,才会调用 onScroll。通常情况下是这样的,但我尝试了延迟其调用:

val runnable = Runnable {
    gestureDetector.onTouchEvent(event)
}
App.instance.timerHandler.postDelayed(runnable, 1000)

如果我进行滚动并在一秒钟内从屏幕上抬起手指,则不会调用onScroll,也不会崩溃。 如果我进行滚动并将手指放在屏幕上超过一秒钟,则会调用onScroll并发生崩溃。

我可以想象有两种方法来修复这个问题:在调用onTouchEvent之前,在我的OnTouchListener中验证事件,或者找出是什么导致GestureDetectoronScroll发送无效的事件。 但我对两者都没有更多的想法。 是否有其他人有想法?

1个回答

6
我一步步地在新的片段中重新构建了这个功能,以隔离问题。滚动视图被包裹在一个周围,以使文本视图成为可抛掷物(惯性滚动),但我还在该文本视图上使用了,以便检测捏合手势,调整文本大小。显然,这会吸收onDown事件,导致周围的滚动视图没有接收到它。
我认为有一种方法可以在两个视图之间共享onDown事件,但在我的情况下,将捏合手势检测器从内部文本视图移动到外部滚动视图更容易,因此滚动手势检测器和捏合手势检测器位于同一个视图上--类似于这样:
val scrollGestureDetector = GestureDetector(this.fragment.activity, ScrollGestureListener(scrollView))
val pinchGestureDetector = GestureDetector(this.fragment.activity, PinchGestureListener(scrollView))
scrollView.setOnTouchListener(OnTouchListener { view, event ->
    scrollGestureDetector.onTouchEvent(event)
    pinchGestureDetector.onTouchEvent(event)
    return@OnTouchListener false
})

internal inner class ScrollGestureListener(view: View) : GestureDetector.SimpleOnGestureListener() {
    override fun onScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean {
        this@DocumentViewer.onDrag()
        return true
    }
}

internal inner class PinchGestureListener(view: View) : ScaleGestureDetector.SimpleOnScaleGestureListener() {
    override fun onScale(detector: ScaleGestureDetector): Boolean {
        this@DocumentViewer.onZoom()
        return true
    }
}

1
哇,我真的很感激你在这方面的调查努力。我的一个应用程序在使用33进行编译时突然崩溃,而我所能找到的只有关于此问题的Google IssueTracker问题(242021191和238920463)。然而,由于你的工作,我已经意识到了一种可以解决这个问题的方法,而不仅仅是等待谷歌解决这个问题。谢谢! - Dave

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接