Android--记录一次触摸事件回收导致的崩溃

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;
        }
    }

错误场景

注意:系统会自动回收我们发起的触摸事件!!!触摸事件只允许回收一次!!!

  1. 我们在调用 event.recycle() 后,系统又调用一次 recycle
  2. 系统调用 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,将系统的事件进行回收。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值