MotionEvent recycled twice!
错误日志
java.lang.RuntimeException: MotionEvent { action=ACTION_UP, actionButton=0, id[0]=0, x[0]=1758.0, y[0]=151.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=46278943, downTime=46278934, deviceId=3, source=0x1002, displayId=0 } recycled twice!
at android.view.InputEvent.recycle(InputEvent.java:134)
at android.view.MotionEvent.recycle(MotionEvent.java:1995)
at android.view.InputEvent.recycleIfNeededAfterDispatch(InputEvent.java:152)
at android.view.InputEventReceiver.finishInputEvent(InputEventReceiver.java:170)
at android.view.ViewRootImpl.finishInputEvent(ViewRootImpl.java:7998)
at android.view.ViewRootImpl.access$2300(ViewRootImpl.java:151)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5220)
at android.view.ViewRootImpl$SyntheticInputStage.onDeliverToNext(ViewRootImpl.java:6096)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5179)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5151)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5218)
at android.view.ViewRootImpl$ViewPostImeInputStage.onDeliverToNext(ViewRootImpl.java:5721)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5179)
at android.view.ViewRootImpl$InputStage.finish(ViewRootImpl.java:5172)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5189)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5155)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5218)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5179)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:5336)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5187)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:5393)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5155)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5218)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5179)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5187)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5155)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:7968)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:7937)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:7894)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:8112)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:206)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:340)
at android.os.Looper.loop(Looper.java:183)
at android.app.ActivityThread.main(ActivityThread.java:7880)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:526)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1034)
错误源码
InputEvent.java
public void recycle() {
if (TRACK_RECYCLED_LOCATION) {
if (mRecycledLocation != null) {
throw new RuntimeException(toString() + " recycled twice!", mRecycledLocation);
}
mRecycledLocation = new RuntimeException("Last recycled here");
} else {
if (mRecycled) { // 只允许回收一次event
throw new RuntimeException(toString() + " recycled twice!");
}
mRecycled = true;
}
}
错误场景
注意:系统会自动回收我们发起的触摸事件!!!触摸事件只允许回收一次!!!
- 我们在调用 event.recycle() 后,系统又调用一次 recycle
- 系统调用 recycle() 后,我们又调用一次 recycle()
我们什么时候会想着调用 event.recycle ?可能有这么一种场景:当我们需要更改触摸事件的坐标时,我们使用 MotionEvent.obtain 复用一个 event 对象并更改 x和y,接着我们再使用 recycle 方法回收之前的 event。代码如下:
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
val ransformEvent = MotionEvent.obtain(ev)
ransformEvent.setLocation(100f, 100f) //
val handled = super.dispatchTouchEvent(ransformEvent)
ev.recycle() // 回收系统返回的 event ,结果就是崩溃了
ransformEvent.recycle() // 回收我们复用的 event,结果是正常
return handled
}
解决错误
既然系统默认会回收触摸事件,我们就不要画蛇添足的去调用 event.recycle,将系统的事件进行回收。