按键分析--APP部分-- OnTouch事件处理流程

5.2.1         OnTouchListener注册和使用

 

1)子类实现View.OnTouchListener,View.OnTouchListener是view的一个接口,

 public class Workspace extends SmoothPagedView

        implements DropTarget, DragSource, DragScroller, View.OnTouchListener,

        DragController.DragListener, LauncherTransitionable, ViewGroup.OnHierarchyChangeListener,

        Insettable, OnScaleGestureListener {

 

 

    @Override

    public boolean onTouch(View v, MotionEvent event) {

    }

 

 

 

2)向目的view注册OnTouchListener监听器,把类自身当作监听器

     public void onChildViewAdded(View parent, View child) {

        CellLayout cl = ((CellLayout) child);

        cl.setOnInterceptTouchListener(this);

    }

 

3)目的view通知监听器,

 

    private OnTouchListener mInterceptTouchListener;

 

    public void setOnInterceptTouchListener(View.OnTouchListener listener) {

        mInterceptTouchListener = listener;

    }

 

 

    @Override

    public boolean onInterceptTouchEvent(MotionEvent ev) {

        if (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)) {

            return true;

        }

 

        if (action == MotionEvent.ACTION_DOWN) {            setTagToCellInfoForPoint((int) ev.getX(), (int) ev.getY());

        }

 

        return false;

    }

 

 

 

 

 

 

 

5.2.2         OnTouchListener栈分析

在launcher里的workspace的onTouch调用栈:

Workspace.onTouch(View, MotionEvent) line: 1506   9)

CellLayout.onInterceptTouchEvent(MotionEvent) line: 904        8)

CellLayout(ViewGroup).dispatchTouchEvent(MotionEvent) line: 2113     

Workspace(ViewGroup).dispatchTransformedTouchEvent(MotionEvent, boolean, View, int) line: 2568 

Workspace(ViewGroup).dispatchTouchEvent(MotionEvent) line: 2202     

Workspace.dispatchTouchEvent(MotionEvent) line: 8001  

FrameLayout(ViewGroup).dispatchTransformedTouchEvent(MotionEvent, boolean, View, int) line: 2568    

FrameLayout(ViewGroup).dispatchTouchEvent(MotionEvent) line: 2202 

AnimationDragLayer(ViewGroup).dispatchTransformedTouchEvent(MotionEvent, boolean, View, int) line: 2568

AnimationDragLayer(ViewGroup).dispatchTouchEvent(MotionEvent) line: 2202    

DragLayer(ViewGroup).dispatchTransformedTouchEvent(MotionEvent, boolean, View, int) line: 2568 

DragLayer(ViewGroup).dispatchTouchEvent(MotionEvent) line: 2202     

FrameLayout(ViewGroup).dispatchTransformedTouchEvent(MotionEvent, boolean, View, int) line: 2568    

FrameLayout(ViewGroup).dispatchTouchEvent(MotionEvent) line: 2202 

LinearLayout(ViewGroup).dispatchTransformedTouchEvent(MotionEvent, boolean, View, int) line: 2568    

LinearLayout(ViewGroup).dispatchTouchEvent(MotionEvent)line: 2202     7)

PhoneWindow$DecorView(ViewGroup).dispatchTransformedTouchEvent(MotionEvent, boolean, View, int) line: 2568      

PhoneWindow$DecorView(ViewGroup).dispatchTouchEvent(MotionEvent) line: 2202   6)

PhoneWindow$DecorView.superDispatchTouchEvent(MotionEvent) line: 2442

PhoneWindow.superDispatchTouchEvent(MotionEvent) line: 1751   5)

Launcher(Activity).dispatchTouchEvent(MotionEvent) line: 2828     4)

PhoneWindow$DecorView.dispatchTouchEvent(MotionEvent) line: 2403 

PhoneWindow$DecorView(View).dispatchPointerEvent(MotionEvent) line: 9522   3

ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl$QueuedInputEvent) line: 4247

ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl$QueuedInputEvent) line: 4097 

ViewRootImpl$ViewPostImeInputStage(ViewRootImpl$InputStage).deliver(ViewRootImpl$QueuedInputEvent) line: 3643

ViewRootImpl$NativePostImeInputStage(ViewRootImpl$InputStage).onDeliverToNext(ViewRootImpl$QueuedInputEvent) line: 3696      

ViewRootImpl$NativePostImeInputStage(ViewRootImpl$InputStage).forward(ViewRootImpl$QueuedInputEvent) line: 3662   

ViewRootImpl$NativePostImeInputStage(ViewRootImpl$AsyncInputStage).forward(ViewRootImpl$QueuedInputEvent) line: 3788      

ViewRootImpl$NativePostImeInputStage(ViewRootImpl$InputStage).apply(ViewRootImpl$QueuedInputEvent, int) line: 3670 

ViewRootImpl$NativePostImeInputStage(ViewRootImpl$AsyncInputStage).apply(ViewRootImpl$QueuedInputEvent, int) line: 3845      

ViewRootImpl$NativePostImeInputStage(ViewRootImpl$InputStage).deliver(ViewRootImpl$QueuedInputEvent) line: 3643     

ViewRootImpl$EarlyPostImeInputStage(ViewRootImpl$InputStage).onDeliverToNext(ViewRootImpl$QueuedInputEvent) line: 3696      

ViewRootImpl$EarlyPostImeInputStage(ViewRootImpl$InputStage).forward(ViewRootImpl$QueuedInputEvent) line: 3662     

ViewRootImpl$EarlyPostImeInputStage(ViewRootImpl$InputStage).apply(ViewRootImpl$QueuedInputEvent, int) line: 3670   

ViewRootImpl$EarlyPostImeInputStage(ViewRootImpl$InputStage).deliver(ViewRootImpl$QueuedInputEvent) line: 3643      

ViewRootImpl.deliverInputEvent(ViewRootImpl$QueuedInputEvent) line: 5939    

ViewRootImpl.doProcessInputEvents() line: 5913      2

ViewRootImpl.enqueueInputEvent(InputEvent, InputEventReceiver, int, boolean) line: 5874 

ViewRootImpl$WindowInputEventReceiver.onInputEvent(InputEvent) line: 6042  

ViewRootImpl$WindowInputEventReceiver(InputEventReceiver).dispatchInputEvent(int, InputEvent) line: 185  

MessageQueue.nativePollOnce(long, int) line: not available [native method]    1

MessageQueue.next() line: 323    

Looper.loop() line: 135 

ActivityThread.main(String[]) line: 5524    

Method.invoke(Object, Object...) line: not available [native method]

ZygoteInit$MethodAndArgsCaller.run() line: 752      

ZygoteInit.main(String[]) line: 642     

 

关键点分析:

1)MessageQueue.nativePollOnce

消息循环,获取到jni层按键发给它的触屏事件,从jni转到java层来处理事件

 

2)ViewRootImpl.doProcessInputEvents

当前窗口的ViewRootImpl获取到事件,并开始处理

 

3)PhoneWindow$DecorView(View).dispatchPointerEvent

DecorView作为root的实例引用,开始接受事件进行处理。

 

4)Launcher(Activity).dispatchTouchEvent

通过cb,跳转到activity

 

5)--7)PhoneWindow.superDispatchTouchEvent

Activity又将事件传给PhoneWindow,逐步在各级child view里面传递,看谁会消耗事件。如果没有消耗,还会传给Activity进行onTouchEvent处理。Activity这里有两个作用,一是Activity实例可以提前捕获touch事件,做特殊处理,二是可以进行onTouchEvent处理。

 

8)--9)CellLayout.onInterceptTouchEvent

这里主要实现了应用层面view间的OnTouchListener。

 



 

5.2.3         OnTouchEvent栈分析

onTouchEvent被实现的地方很多,调用流程也各不相同,以下举例分析。

 

在launcher里的workspace里,onTouchEvent 和 OnTouchListener调用栈差异很小,也很微秒(底层是一样的,在栈顶附近略有区别):

 

Workspace(PagedView).onTouchEvent(MotionEvent) line: 2457      

Workspace(View).dispatchTouchEvent(MotionEvent) line: 9302

Workspace(ViewGroup).dispatchTransformedTouchEvent(MotionEvent, boolean, View, int) line: 2562 

Workspace(ViewGroup).dispatchTouchEvent(MotionEvent) line: 2245     

Workspace.dispatchTouchEvent(MotionEvent) line: 8001  

FrameLayout(ViewGroup).dispatchTransformedTouchEvent(MotionEvent, boolean, View, int) line: 2568    

 

 

Workspace.onTouch(View, MotionEvent) line: 1506   

CellLayout.onInterceptTouchEvent(MotionEvent) line: 904        

CellLayout(ViewGroup).dispatchTouchEvent(MotionEvent) line: 2113     

Workspace(ViewGroup).dispatchTransformedTouchEvent(MotionEvent, boolean, View, int) line: 2568 

Workspace(ViewGroup).dispatchTouchEvent(MotionEvent) line: 2202     

Workspace.dispatchTouchEvent(MotionEvent) line: 8001  

 

Workspace和CellLayout都是ViewGroup的子类,却一个执行了View的dispatchTouchEvent ,一个执行了ViewGroup的dispatchTouchEvent,onTouchEvent只在View里被调用,所以能执行最终子类的onTouchEvent。

 

这种流程的区别在(ViewGroup).dispatchTransformedTouchEvent里,标黄的两个if语句决定了流程差异,

     private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,

            View child, int desiredPointerIdBits) {

 

        // Calculate the number of pointers to deliver.

        final int oldPointerIdBits = event.getPointerIdBits();

        final int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits;

 

        // If the number of pointers is the same and we don't need to perform any fancy

        // irreversible transformations, then we can reuse the motion event for this

        // dispatch as long as we are careful to revert any changes we make.

        // Otherwise we need to make a copy.

        final MotionEvent transformedEvent;

        if (newPointerIdBits == oldPointerIdBits) {

            if (child == null || child.hasIdentityMatrix()) {

                if (child == null) {

                    handled = super.dispatchTouchEvent(event);

                } else {

                    final float offsetX = mScrollX - child.mLeft;

                    final float offsetY = mScrollY - child.mTop;

                    event.offsetLocation(offsetX, offsetY);

 

                    handled = child.dispatchTouchEvent(event);

 

                    event.offsetLocation(-offsetX, -offsetY);

                }

                return handled;

            }

            transformedEvent = MotionEvent.obtain(event);

        } else {

            transformedEvent = event.split(newPointerIdBits);

        }

 

 

其中,desiredPointerIdBits又根据调用者的流程和参数而不同。在其上级调用中,mFirstTouchTarget是关键因素,标识当前根ViewGoup里,哪些view能接收和处理按键,mFirstTouchTarget链表的元素通过addTouchTarget添加进去。这个流程待后续详细分析。

 

 

另,上面讲的onTouchEvent都是view里面的处理,如果onTouchEvent在activity里面,它一般是用来处理触点在控件外的情形的。




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值