ViewRootImpl事件分发笔记

  • 用户点击屏幕产生触摸行为,该触摸行为由底层硬件捕获并传递。
    硬件 -> ViewRootImpl -> DecorView -> PhoneWindow -> Activity

  • 在ViewRootImpl中准备了一条InputStage链。InputStage是个抽象类,有以下几个实现类,并形成单向链:NativePreImeInputStage -> ViewPreImeInputStage -> ImeInputStage -> EarlyPostImeInputStage -> NativePostImeInputStage -> ViewPostImeInputStage -> SyntheticInputStage.

  • ViewRootImpl收到触摸事件后经历了如下方法:dispatchInputEvent() -> enqueueInputEvent() -> doProcessInputEvents() -> deliverInputEvent()。其中enqueueInputEvent()中生成了QueuedInputEvent,它封装了InputEvent和InputEventReceiver。在deliverInputEvent()中把QueuedInputEvent交个InputStage链逐一处理并传递。InputStage处理事件的方法为onProcess,对于点击事件,ViewPostImeInputStage可以处理它。下面是ViewPostImeInputStage.onProcess:
        @Override
        protected int onProcess(QueuedInputEvent q) {
            if (q.mEvent instanceof KeyEvent) {
                return processKeyEvent(q);
            } else {
                // If delivering a new non-key event, make sure the window is
                // now allowed to start updating.
                handleDispatchWindowAnimationStopped();
                final int source = q.mEvent.getSource();
                if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
                    return processPointerEvent(q);
                } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
                    return processTrackballEvent(q);
                } else {
                    return processGenericMotionEvent(q);
                }
            }
        }

在ViewPostImeInputStage里面有判断是键盘事件还是触摸事件,这里我们只看触摸事件,调用到了processPointerEvent(q)方法

private int processPointerEvent(QueuedInputEvent q) {
        final MotionEvent event = (MotionEvent)q.mEvent;
        mAttachInfo.mUnbufferedDispatchRequested = false;
        boolean handled = mView.dispatchPointerEvent(event);
        ...
        return handled ? FINISH_HANDLED : FORWARD;
}

而这里调用到了mView.dispatchPointerEvent,这里的mView就是DecorView。
再看View的dispatchPointerEvent

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 Callback cb = getCallback();
      return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}

可以看到,这里调用了callback.dispatchTouchEvent,Callback是Window里面的一个接口

public interface Callback {
       ...
       public boolean dispatchKeyEvent(KeyEvent event);
       ...
       public boolean dispatchTouchEvent(MotionEvent event);
}

而实现了Callback的正是Activity

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback {
        ..
}

而在Activity的attach方法中

final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
        ...
        mWindow = new PhoneWindow(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
  }

而Activity收到触摸事件后又回传给了DecorView,下面是Activity的dispatchTouchEvent()

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

PhoneWindow的superDispatchTouchEvent()如下:

@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
       return mDecor.superDispatchTouchEvent(event);
}

DecorView的superDispatchTouchEvent()如下:

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

接下来就是常见的事件分发机制了。

参考文章:
https://www.jianshu.com/p/9e6c54739217

发布了37 篇原创文章 · 获赞 7 · 访问量 1万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 数字50 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览