SimpleOnGestureListener.onScroll 收到空值并崩溃

问题描述 投票:0回答:2

我正在使用手势检测器从滚动视图捕获滚动事件:

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 {
        [email protected]()
        return true
    }
}

当使用compileSdkVersion 30时,我的应用程序会在

onScroll
函数上崩溃,因为它总是收到第一个参数的空值。我通过将第一个参数设为可选来解决这个问题:

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

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

this SO post的评论说:“如果手势检测器以外的其他东西消耗了 ACTION_DOWN 事件,你就会遇到这样的崩溃。”但我不知道还能做什么。我在此片段中的其他一些视图上有手势检测器,但如果我注释掉所有这些代码,崩溃仍然存在。

我临时将

onDown
的实现添加到我的
ScrollGestureListener
中,但它从未被调用,因此这似乎与 ACTION_DOWN 注释有关。

查看

GestureDetector.java
的源代码,我发现它发送到
onScroll
的第一个参数是
mCurrentDownEvent
,因此这似乎也与 ACTION_DOWN 注释相关。但是,如果我在 Android Studio 中向
GestureDetector.java
添加断点,
mCurrentDownEvent
永远不会显示为 null。此外,它始终与作为第二个参数传递的事件相同 (
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)

在致电

OnTouchListener
之前,我尝试在我的
onTouchEvent
中添加某种检查 - 像这样:

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

但是

event
这里永远不会为空,并且在查看它的属性时,我没有看到任何可以检查以确定它是否会导致崩溃的内容。

另一个潜在的线索是,只有在调用

onScroll
时我的手指仍在屏幕上时才会调用
onTouchEvent
。通常情况就是这样,但我尝试像这样延迟它的调用:

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

然后,如果我执行滚动并在一秒钟内将手指从屏幕上抬起,则不会调用

onScroll
并且不会发生崩溃。如果我执行滚动并将手指放在屏幕上超过一秒,则会调用
onScroll
并发生崩溃。

我可以想象两种方法来解决此问题:在调用

OnTouchListener
之前验证我的
onTouchEvent
中的事件,或者找出导致
GestureDetector
onScroll
发送无效事件的原因。但我对这两件事都没有想法了。还有人有想法吗?

android kotlin gesture ontouchlistener
2个回答
6
投票

我在新片段中一步一步地重建此功能以隔离问题。滚动视图包裹在

TextView
周围,以便使文本视图可滑动(惯性滚动),但我在该文本视图上也有一个
OnTouchListener
,这样我就可以检测捏合手势,以调整文本大小。显然,这正在吸收
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 {
        [email protected]()
        return true
    }
}

internal inner class PinchGestureListener(view: View) : ScaleGestureDetector.SimpleOnScaleGestureListener() {
    override fun onScale(detector: ScaleGestureDetector): Boolean {
        [email protected]()
        return true
    }
}

0
投票

我也遇到了这个问题,对我有用的解决方案之一是将侦听器包装在

java
类中,并将
MotionEvent
设为
Nullable

class CustomSimpleOnGestureListener extends GestureDetector.SimpleOnGestureListener {

    private final CustomScrollGestureListener listener;

    public CustomSimpleOnGestureListener(CustomScrollGestureListener listener) {
        this.listener = listener;

    }

    @Override
    public boolean onScroll(@Nullable MotionEvent e1, @Nullable MotionEvent e2, float distanceX, float distanceY) {
        return listener.onScroll(distanceX, distanceY);
    }
}

然后将监听器设置为对象

private val mListener = CustomSimpleOnGestureListener(object : CustomScrollGestureListener {
    override fun onScroll(distanceX: Float, distanceY: Float): Boolean {
        // Your code
        return true
    }
})
© www.soinside.com 2019 - 2024. All rights reserved.