androidkotlinandroid-gestureandroid-touch-eventkotlin-java-interop

"Parameter specified as non-null is null" when using GestureDetector.SimpleOnGestureListener() onScroll() function


I am using the GestureDetector.SimpleOnGestureListener() to react to UserGestures and expand a BottomSheet.

The problem is that a small percentage of the users experience the following crash. ( stacktrace stripped to make the question more readable)

Fatal Exception: java.lang.NullPointerException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkNotNullParameter, parameter e1 at com.app.ui.fragments.HomeFragment$MyGestureListener.onScroll(:2) at android.view.GestureDetector.onTouchEvent(GestureDetector.java:784) at androidx.core.view.GestureDetectorCompat$GestureDetectorCompatImplJellybeanMr2.onTouchEvent(GestureDetectorCompat.java:484) at androidx.core.view.GestureDetectorCompat.onTouchEvent(GestureDetectorCompat.java:548) at com.app.ui.fragments.HomeFragment.onCreateView$lambda-24(HomeFragment.kt:427) at com.app.ui.fragments.HomeFragment.$r8$lambda$UnvNeUUw-6dzbc2zrdFAHiK2duI() at com.app.ui.fragments.HomeFragment$$ExternalSyntheticLambda35.onTouch(:2) at android.view.View.dispatchTouchEvent(View.java:15072) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3917) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:3581)

And this is my implementation of the class.

    inner class MyGestureListener : GestureDetector.SimpleOnGestureListener() {
    override fun onDown(e: MotionEvent): Boolean {
        return true
    }

    override fun onScroll(
        e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float
    ): Boolean {
        val diffY: Float = (e1.y.let { e2.y.minus(it) } ?: 0).toFloat()
        if (diffY < 0) {
            Log.d("====ON SCROLL====", "On Scroll top")
            bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
            binding.root.setOnClickListener(null)
        }
        return true
    }
}

Used like this

val mDetector = GestureDetectorCompat(requireContext(), MyGestureListener())
binding.root.setOnTouchListener { v, event ->
            mDetector.onTouchEvent(event)
            v.performClick()
        }

The screen in which this is used then display a bottomSheet dialog with a recyclerView which allows the user to scroll and press on the items inside the list. The crash usually occurs when users scroll in this recyclerView.

I can't seem to figure out what's wrong with the written code, since the function overriden must have matching signature, so making e1 nullable is not possible.

Any advice is appreciated.

EDIT

After more investigation, this issue occures only after updating the Target and Compile SDK to API level 33. This forced me to make the values non nullable. For previous API level 32 and lower, this code worked as intended and without crashes ( since e1 can be nullable).

inner class MyGestureListener : GestureDetector.SimpleOnGestureListener() {
    override fun onDown(e: MotionEvent): Boolean {
        return true
    }

override fun onScroll(
    e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float
): Boolean {
    val diffY: Float = (e1.y.let { e2.y.minus(it) } ?: 0).toFloat()
    if (diffY < 0) {
        Log.d("====ON SCROLL====", "On Scroll top")
        bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
        binding.root.setOnClickListener(null)
    }
    return true
}

}


Solution

  • I managed to find the issue causing the crash in my case. It was because of a standard Bottom Sheet ( not modal ) that was being displayed on top of a fragment that had this gesture listener set up.

    As a possible workaround for now, disabling the listener when the Bottom Sheet is expanded seems to have solved the crash.

    Hope this helps anyone else with this issue