View的事件分发_ACTION_MOVE的坑

0,,参考

Android 8.0.0 源码

 

1,问题

通常 在dispatchTouchEvent或onTouchEvent的方法 返回 true时,当前的View 就会按照 「ACTION_DOWN -> ACTION_MOVE -> ACTION_MOVE -> 无数个ACTION_MOVE -> ACTION_CANCEL 或 ACTION_UP」的顺序执行

那么,ACTION_MOVE的触发,是在View中循环触发的,还是通过 DecorView 分发下来的???

 

2,测试方案

public class BView extends LinearLayout {
    public BView(Context context) {
        super(context);
    }

    public BView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    private int start_b = 8;

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_MOVE) {
            if (start_b-- > 0) {
                int a = 10; // 啥也不敢,只是占个位置
            } else {
                LogUtil.v("start debug"); // 从这里开始debug, 就可以看到调用链,从哪里来的
            }
        }

        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean defaultResult = super.onTouchEvent(event);
        LogUtil.v("defaultResult = " + defaultResult);
        return true;    // 返回true,当前View处理事件,才会出现Action_Move
    }
}

如上图,我们在 dispatchTouchEvent中,加入一个常量去控制。然后,在常量小于0的时候,debug一个断点。这样,就可以排除其它的调用。而是专注于看 ACTION_MOVE 触发的来源。到底是,内部View的递归,还是 DecorView的dispatch

测试结果:

ACTION_MOVE的调用链 是 DecorView中的dispatch,调用链往上找依次是:

BView.dispatchTouchEvent()
LinearLayout.dispatchTouchEvent()
LinearLayout.dispatchTransformedTouchEvent()
FrameLayout.dispatchTouchEvent()    // 这个就是熟悉的 android.R.id.content
FrameLayout.dispatchTransformedTouchEvent()
LinearLayout.dispatchTouchEvent()
LinearLayout.dispatchTransformedTouchEvent()
DecorView.dispatchTouchEvent()    // 熟悉的DecorView
DecorView.superDispatchTouchEvent()    
PhoneWindows.superDispatchTouchEvent()    // 熟悉的PhoneWindows
Activity.dispatchTouchEvent()    // 熟悉的Activity
DecorView.dispatchTouchEvent()
DecorView.dispatchPointerEvent()
ViewRootImpl.processPointerEvent()    // 熟悉的ViewRootImpl
ViewRootImpl.processPointerEvent()
ViewRootImpl.deliver()
ViewRootImpl.onDeliverToNext()  // 其实,一般到这里就算结束了,不过还是多贴一些。
... 
Choreographer.doCallbacks
Choreographer.doFrame
Choreographer.FrameDisplayEventReceiver.run    // 熟悉的人都知道,这里是View绘制的源头
Handler.handleCallback
Handler.dispatchMessage    // 这里就是「同步屏障」的分发位置,和一般的Handler也很相似
Looper.loop
ActivityThread.main    // 这里就是,Java主线程入口了
RuntimeInit.run
ZygoteInit.main    // 这里就是程序的开始了,到这里就彻底没当前进程的调用链了

 

结论:ACTION_DOWN、ACTION_MOVE、ACTION_UP也好,所有的事件都是从ViewRootImpl那里来的,理解成DecorView开始分发,也是可以的。

 

题外话 + 闲聊:

带着这个结论,再去看ViewGroup.java 中的 dispatchTouchEvent 的实现,你会发现 里面也是 利用全局变量,去记录状态。然后,处理不同的MotionEvent的不同情况,例如:mFirstTouchTarget。

这里和我们平时写代码基本没啥两样。

这里也在想,其实ViewRootImpl 要求在原始线程中绘制View,其实也是逼不得已。

 

 

 

 

 

 

 

 

 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值