Android TIRAMISU GestureDetector问题记录

627 阅读2分钟

Android TIRAMISU已经发布了,最近也是把公司App的TargetSdk升级到了TIRAMISU。

项目中用到GestureDetector来实现手势返回功能,该类下的几个监听API在TIRAMISU有变化,如下:

// TIRAMISU之前
public class GestureDetector {
    
    ....
    
    /**
     * A convenience class to extend when you only want to listen for a subset
     * of all the gestures. This implements all methods in the
     * {@link OnGestureListener}, {@link OnDoubleTapListener}, and {@link OnContextClickListener}
     * but does nothing and return {@code false} for all applicable methods.
     */
    public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener,
            OnContextClickListener {

        public boolean onSingleTapUp(MotionEvent e) {
            return false;
        }

        public void onLongPress(MotionEvent e) {
        }

        public boolean onScroll(MotionEvent e1, MotionEvent e2,
                float distanceX, float distanceY) {
            return false;
        }

        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                float velocityY) {
            return false;
        }

        public void onShowPress(MotionEvent e) {
        }

        public boolean onDown(MotionEvent e) {
            return false;
        }

        public boolean onDoubleTap(MotionEvent e) {
            return false;
        }

        public boolean onDoubleTapEvent(MotionEvent e) {
            return false;
        }

        public boolean onSingleTapConfirmed(MotionEvent e) {
            return false;
        }

        public boolean onContextClick(MotionEvent e) {
            return false;
        }
    }
   
    ....
}

// TIRAMISU
public class GestureDetector {
    
    ....

    /**
     * A convenience class to extend when you only want to listen for a subset
     * of all the gestures. This implements all methods in the
     * {@link OnGestureListener}, {@link OnDoubleTapListener}, and {@link OnContextClickListener}
     * but does nothing and return {@code false} for all applicable methods.
     */
    public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener,
            OnContextClickListener {

        public boolean onSingleTapUp(@NonNull MotionEvent e) {
            return false;
        }

        public void onLongPress(@NonNull MotionEvent e) {
        }

        public boolean onScroll(@NonNull MotionEvent e1, @NonNull MotionEvent e2,
                float distanceX, float distanceY) {
            return false;
        }

        public boolean onFling(@NonNull MotionEvent e1, @NonNull MotionEvent e2, float velocityX,
                float velocityY) {
            return false;
        }

        public void onShowPress(@NonNull MotionEvent e) {
        }

        public boolean onDown(@NonNull MotionEvent e) {
            return false;
        }

        public boolean onDoubleTap(@NonNull MotionEvent e) {
            return false;
        }

        public boolean onDoubleTapEvent(@NonNull MotionEvent e) {
            return false;
        }

        public boolean onSingleTapConfirmed(@NonNull MotionEvent e) {
            return false;
        }

        public boolean onContextClick(@NonNull MotionEvent e) {
            return false;
        }
    }
    
    ....
}

SimpleOnGestureListener实现了所有的监听,可以看到方法中的参数都加上了@NunNull注解。由于项目是用Kotlin开发,于是代码中需要进行如下调整:

// TIRAMISU之前
val gestureDetectorCompat = GestureDetectorCompat(this, object : GestureDetector.SimpleOnGestureListener() {
    override fun onDown(e: MotionEvent?): Boolean {
        return super.onDown(e)
    }

    override fun onFling(e1: MotionEvent?, e2: MotionEvent?, velocityX: Float, velocityY: Float): Boolean {
        return super.onFling(e1, e2, velocityX, velocityY)
    }
    
    ....
})
        
// TIRAMISU
val gestureDetectorCompat = GestureDetectorCompat(this, object : GestureDetector.SimpleOnGestureListener() {
    override fun onDown(e: MotionEvent): Boolean {
        return super.onDown(e)
    }

    override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
        return super.onFling(e1, e2, velocityX, velocityY)
    }
    
    ....
})

改起来还是很简单的,只要把方法中参数可为空的符号去掉即可。但是改完上线运行了一段时间后,收集到了崩溃信息如下:

企业微信截图_e3758f2f-1735-4773-a61f-66e407a0db09.png

根据信息可以看出,onFling方法中的e1参数注解标识不可为空,但是传入了空值导致崩溃。

base类中的代码实现:

class AppBaseActivity : AppCompatActivity() {

    private var gestureDetectorCompat: GestureDetectorCompat? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val point = Point()
        windowManager.defaultDisplay.getRealSize(point)
        val screenWidth = resources.displayMetrics.widthPixels
        val screenHeight = point.y
        val edgeSize = (screenWidth * 0.035).toInt()
        gestureDetectorCompat = GestureDetectorCompat(this, object : GestureDetector.SimpleOnGestureListener() {
            override fun onDown(e: MotionEvent): Boolean {
                onUserInteraction()
                val finalScreeWidth = if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
                    screenHeight
                } else {
                    screenWidth
                }
                return e.x < edgeSize || e.x > finalScreeWidth - edgeSize
            }

            override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
                val distantX = abs(e2.x - e1.x)
                val distantY = abs(e2.y - e1.y)
                val finalScreeWidth = if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
                    screenHeight
                } else {
                    screenWidth
                }

                if (e1.x < edgeSize || e1.x > finalScreeWidth - edgeSize) {
                    if (distantX > distantY) {
                        onBackPressedDispatcher.onBackPressed()
                        return true
                    }
                }
                return super.onFling(e1, e2, velocityX, velocityY)
            }
        })
    }  

    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
        val consumeMotionEvent = gestureDetectorCompat?.onTouchEvent(ev) ?: false
        return if (consumeMotionEvent) {
            true
        } else {
            super.dispatchTouchEvent(ev)
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        if (gestureDetectorCompat != null) {
            gestureDetectorCompat = null
        }
    }
}

个人认为代码实现没啥大问题,在自己的测试机上测试功能也正常,记录一下该问题,希望有人可以帮我解惑😂。