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)
}
....
})
改起来还是很简单的,只要把方法中参数可为空的符号去掉即可。但是改完上线运行了一段时间后,收集到了崩溃信息如下:
根据信息可以看出,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
}
}
}
个人认为代码实现没啥大问题,在自己的测试机上测试功能也正常,记录一下该问题,希望有人可以帮我解惑😂。