I'm using a gesture detector to capture scroll events from a scroll view:
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
}
}
When using compileSdkVersion 30, my app would crash on the onScroll
function because that always received a null value for the first argument. I worked around that by making the first argument optional:
override fun onScroll(e1: MotionEvent?, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean {
Now I'm trying to update my compileSdkVersion to 33, and the above line will no longer compile. But if I revert back to the standard function signature, then the app crashes again when I scroll the scroll view.
A comment on this SO post says, "You'll get a crash like this if something other than the gesture detector consumes ACTION_DOWN events." But I can't figure out what else would be doing that. I have gesture detectors on some other views in this fragment, but if I comment out all that code, the crashes remain.
I temporarily added an implementation of onDown
to my ScrollGestureListener
and it was never called, so that seems related to the ACTION_DOWN comment.
Looking at the source code for GestureDetector.java
, I see that the first argument it sends to onScroll
is mCurrentDownEvent
, so that also seems related to the ACTION_DOWN comment. But if I add breakpoints to GestureDetector.java
in Android Studio, mCurrentDownEvent
never shows as null. Also, it's always the same as the event passed as the second argument (ev
) -- GestureDetector
simply sets mCurrentDownEvent
to a copy of ev
.
It looks like the crash occurs when GestureDetector
calls onScroll
, because a breakpoint in my onScroll
method isn't reached, and the same crash happens if I remove my onScroll
override -- apparently just calling the superclass implementation of onScroll
causes a crash. Here's what appears in the console:
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)
I've tried adding some kind of check to my OnTouchListener
, before calling onTouchEvent
-- something like this:
if (event != null) {
gestureDetector.onTouchEvent(event)
}
But event
is never null here, and when looking at its properties, I don't see anything I could check to determine whether it will cause a crash.
Another potential clue is that onScroll
is only called if my finger is still on the screen when calling onTouchEvent
. That's normally the case, but I tried delaying its call like this:
val runnable = Runnable {
gestureDetector.onTouchEvent(event)
}
App.instance.timerHandler.postDelayed(runnable, 1000)
Then if I perform a scroll and lift my finger off the screen within one second, onScroll
is not called and there is no crash. If I perform a scroll and leave my finger on the screen for more than one second, onScroll
is called and there is a crash.
I can imagine two approaches to fixing this: validating the event in my OnTouchListener
before calling onTouchEvent
, or figuring out what is causing GestureDetector
to send invalid events to onScroll
. But I've run out of ideas on both. Does anyone else have an idea?