本篇是事件分发的终篇(涉及到其他知识点先不细说),建议先研究下View篇 和 ViewGroup篇 。可有童鞋就说了,就喜欢先看总体框架、流程,再仔细琢磨,那么咱就开工!
本篇继续基于APILevel 25(7.1.1) 源码,理解为先、各版本代码可能有差别,核心部分是一致的。

1、ViewGroup、Activity怎么连接起来的?

ViewGroup篇中开头的demo和图片已经说了,事件大概是从Activity->ViewGroup->View传递的,上篇说了ViewGroup->View的部分。本篇就研究下Activity->ViewGroup。
我总是喜欢从下往上寻找问题的根源,所以我们还是从被事件分发到的ViewGroup来说,比如上篇demo的MyLinearLayout。先不着急开始,工欲善其事,必先利其器。
这里我们需要借助Hierarchy View
1、先运行ViewGroup篇的demo
2、Android studio(此处为2.3.1) 中打开Android Device Monitor

3、切换试图,打开Hierarchy View

4、load the view hierarchy into the tree view

5 、这时就可以在右边的tree view中看到了,为了避免东西太多,我们将MainActivity extends Activity,你也不用改,原理一致。tree view显示如下。看不太清的话,可以放大页面或另存本地查看。

总结,可以看到MyLinearLayout的前面是id为content的FragmentLayout,一直往前,是一个DecorView。

2、找到DecorView

1、如果是Android Studio,先下载source,如下图,这里选中的是Sources for Android 25

2、双击shift,输入DecorView

3、DecorView是什么

首先,定义这个类的时候,就暴露了自己public class DecorView extends FrameLayout **。
既然DecorView也是一个ViewGroup,那肯定也有dispatchTouchEvent方法,可是既然是根view,有没有特殊之处呢?我们还是按照正规军的打法,找到dispatchTouchEvent

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

What are you 弄啥嘞!super.dispatchTouchEvent(ev)虽说还是ViewGroup的动作,可cb.dispatchTouchEvent(ev)是什么,Callback是什么,mWindow又是什么鬼?
别慌,你这个类中找一找。简单来说,你会发现Callback就是Window的事件回调接口;mWindow却是PhoneWindow 。

DecorView(Context context, int featureId, PhoneWindow window,        WindowManager.LayoutParams params) {    ...    setWindow(window);    ...}void setWindow(PhoneWindow phoneWindow) {    mWindow = phoneWindow;    ...}

4、PhoneWindow和DecorView的联系

首先,你会惊喜的发现,里面有个setContentView,有木有很兴奋,有木有?!

@Overridepublic void setContentView(int layoutResID) {    // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window    // decor, when theme attributes and the like are crystalized. Do not check the feature    // before this happens.    if (mContentParent == null) {        installDecor();    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {        mContentParent.removeAllViews();    }    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {        final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,                getContext());        transitionTo(newScene);    } else {        mLayoutInflater.inflate(layoutResID, mContentParent);    }    mContentParent.requestApplyInsets();    final Callback cb = getCallback();    if (cb != null && !isDestroyed()) {        cb.onContentChanged();    }    mContentParentExplicitlySet = true;}

其中的installDecor(),深入去看,有new DecorView和mDecor.setWindow(this),这样一来,两者之间互相叫“亲”了。

5、PhoneWindow的dispatchTouchEvent

根据以往,事件往往都是从dispatchTouchEvent开始的,可是在PhoneWindow中却找不到。但有个

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

而mDecor(DecorView)中的mDecor.superDispatchTouchEvent最终也只是调用了自己的super.dispatchTouchEvent,来到了父类FrameLayout(ViewGroup)的dispatchTouchEvent,最终又回到了经典版ViewGroup事件分发的轨道上了。

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

那我们就有疑问了,DecorView是RootView,里面会走到mWindow.getCallback().dispatchTouchEvent,我们就去看看getCallback能得到什么。
getCallback方法是在Window中的,PhoneWindow extends Window。

public void setCallback(Callback callback) {    mCallback = callback;}public final Callback getCallback() {    return mCallback;}

setCallback方法,最终你会发现是在Activity的attach方法中调用的,此处还看到了 new PhoneWindow。

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,        Window window) {    attachBaseContext(context);    mFragments.attachHost(null /*parent*/);    mWindow = new PhoneWindow(this, window);    mWindow.setWindowControllerCallback(this);    mWindow.setCallback(this);    ...}

那么现在PhoneWindow和Activity也关联起来,那岂不就是三者就关联起来了嘛。mWindow.setCallback(this)的原因,是因为Activity implements Window.Callback。

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

也就是说DecorView中的dispatchTouchEvent,也就是最终调用了Activity的dispatchTouchEvent方法,谁让Activity也是一个Callback呢。

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

其中第5 行其实是调用了PhoneWindow.superDispatchTouchEvent,而PhoneWindow其实也是调用了DecorView.superDispatchTouchEvent。
真实一环套一环,套路何其深啊!
3 行,ACTION_DOWN每次都能走到,也是事件的开始标识。

6、DecorView、PhoneWindow、Activity的关系图

最初始时,事件是首先到了DecorView的dispatchTouchEvent(Window通过injectInputEvent跟ViewRootImpl关联….好多东西,此文略去),但是通过几者的关联,最终调用Activity中的dispatchTouchEvent方法,然后又回调DecorView的superDispatchTouchEvent,也就是直接调用了父类ViewGroup的dispatchTouchEvent,从此正式走上经典路线。
PhoneWindow就是起到了关联,各种接收命令、指挥作战的作用。

7、View、ViewGroup、Activity事件分发流程图示

话一说就多,直接上图(流程示意图,注意仅是示意图,便于理解)
1、中间没有消费掉事件时,交给Activity处理

2、View消费掉

3、ViewGroup消费掉

Sorry,戛然而止,结束了。能力不足,语言组织有待提高,不过希望能帮到大家,哪怕能引起一点点疑问。
事件分发机制源码解析暂时告一段落。里面还有诸多知识点,希望自己不懈怠,后续补充。
加油!

更多相关文章

  1. Android之调用百度地图API规划当前位置到指定位置的路线
  2. Android(安卓)DragAndDrop API 拖拽效果 交换ListView的Item值
  3. 退出程序时尚未finish的activity出现问题
  4. EventBus 3.0进阶-Delivery Threads (ThreadMode)传送线程(线程模
  5. 关于android 百度地图离线包的调用问题
  6. Android(安卓)调用前置摄像头
  7. Android(安卓)View相关-事件分发机制详解-View
  8. Android使用AIDL设计和调用远程接口
  9. Android(安卓)surfaceflinger (4) -Vsync产生上报流程

随机推荐

  1. Android开发学习笔记(十)实现一个简易的开
  2. Android使用Intent启动其他非系统应用程
  3. Android中bluetooth的架构
  4. Android(安卓)activity与service中的子线
  5. Eclipse如何打包生成Apk安装包实例(图)
  6. [android架构篇]mvp+rxjava+retrofit+eve
  7. Android(安卓)Aidl 机制
  8. Platform Dependent Compilation 多平台
  9. Android连接、断开蓝牙扫描枪时屏幕刷新
  10. 如何在Android中实现悬浮Activity