Andorid 中TouchEvent理解(一) Event从底层到DecorView

想总结一下android的touch事件的分发机制,decorView是应用层分发机制的起点,decorView 的事件是从哪里来的呢。

        线程同步:

         在驱动层收到touch的事件的线程肯定不在我们的Activity的主线程里,如何将事件同步到主线程里,请看Handler的分析点击打开链接。Handler中ThreadLocal<Loop>是单实例的。查阅了资料发现在底层就可以通过MessageQueue来获取当前线程的Looper,底层有类似Handler,也就是说,当底层调用dispatchInputEvent()来驱动事件的时候,已经是在同步了的主线程循环中的了。


事件从底层到DecorView:

因为牵扯到Activity的启动过程Window的添加,这些先不去管它,先来看一下当前的这块积木,

ViewRootImpl.java,在这个类中有个setView方法,这里set的这个mView就是decorView,这段代码中有new了一个这样的对象。

mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
                            Looper.myLooper());

看一下这个类的具体代码,

final class WindowInputEventReceiver extends InputEventReceiver {
        public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
            super(inputChannel, looper);
        }

        @Override
        public void onInputEvent(InputEvent event) {
            enqueueInputEvent(event, this, 0, true);
        }

        @Override
        public void onBatchedInputEventPending() {
            if (mUnbufferedInputDispatch) {
                super.onBatchedInputEventPending();
            } else {
                scheduleConsumeBatchedInput();
            }
        }

        @Override
        public void dispose() {
            unscheduleConsumeBatchedInput();
            super.dispose();
        }
    }

构造函数中将主线程的Looper传了进来,和设想差不多,然后去看一下父类的源码,不贴出来了,直接看一下构造

public InputEventReceiver(InputChannel inputChannel, Looper looper) {
        if (inputChannel == null) {
            throw new IllegalArgumentException("inputChannel must not be null");
        }
        if (looper == null) {
            throw new IllegalArgumentException("looper must not be null");
        }

        mInputChannel = inputChannel;
        mMessageQueue = looper.getQueue();
        mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
                inputChannel, mMessageQueue);

        mCloseGuard.open("dispose");
    }

果然将looper中的MessageQueue取了出来,并且使用native方法传到了C层中,C层可以将Event时间插入到主线程的MessageQueue中了,C层代码不再关注。

在这个类中,还有另外的一个方法,如下

// Called from native code.
    @SuppressWarnings("unused")
    private void dispatchInputEvent(int seq, InputEvent event) {
        mSeqMap.put(event.getSequenceNumber(), seq);
        onInputEvent(event);
    }

方法由底层驱动,调用onInputEvent这个方法,这个方法在子类(WindowInputEventReceiver)中重写,

调用enqueueInputEvent(),

调用doProcessInputEvents();

调用deliverInputEvent(q);

调用stage.deliver(q); 解释一下这个Stage是个责任链,根据责任链选择处理此事件的stage,对于Touch是事件来说。ViewPostImeInputStage这个责任链节点来处理。具体不分析了。。android的各种类型事件太多了,责任链自然有它的逻辑不去管它。

调用apply()->onProcess()

调用processPointerEvent()

final View eventTarget =
                    (event.isFromSource(InputDevice.SOURCE_MOUSE) && mCapturingView != null) ?
                            mCapturingView : mView;
            mAttachInfo.mHandlingPointerEvent = true;
            boolean handled = eventTarget.dispatchPointerEvent(event);

调用View的dispatchPointerEvent();到View的代码里找一下。

 public final boolean dispatchPointerEvent(MotionEvent event) {
        if (event.isTouchEvent()) {
            return dispatchTouchEvent(event);
        } else {
            return dispatchGenericMotionEvent(event);
        }
    }


在DecorView中dispatchTouchEvent被覆盖重写如下

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        final Window.Callback cb = mWindow.getCallback();
        return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
                ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
    }



这里的Callback即是在ActivityThread中被复制的Activity回调,有Activity的时候将事件传递到Activity中,没有Activity的时候就自己来处理。

在Activity中有如下代码

public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onUserInteraction();
        }
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        return onTouchEvent(ev);
    }

在Acitvity中的这个回调,又使用了Window的superDispatchTouchEvent()这个方法,相当于TouchEvent到Activity中转了一圈,又回到了Window中使用View来处理。如果View中处理了,Activity中的onTouchEvent()就不会调用,如果View没有处理,交给Activity的onTouchEvent()来处理。Acitvity中最终是要处理的,返回值似乎无效了,只是简单的回调使用,这里没有对返回值做任何的处理。不知道这样理解对不对。

代码如下:

public boolean superDispatchTouchEvent(MotionEvent event) {
        return super.dispatchTouchEvent(event);
    }

还是调用了ViewGroup的dispatchTouchEvent()从这里开始真正的View中分发了。。

android还有个好多都不懂啊,慢慢阅读吧。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值