Android面试题--事件处理

1、Handler 机制

Android 中主线程也叫 UI 线程,那么从名字上我们也知道主线程主要是用来创建、更新 UI 的,而其他耗时操作,比如网络访问,或者文件处理,多媒体处理等都需要在子线程中操作,之所以在子线程中操作是为了保证 UI 的流畅程度,手机显示的刷新频率是 60Hz,也就是一秒钟刷新 60 次,每16.67 毫秒刷新一次,为了不丢帧,那么主线程处理代码最好不要超过 16 毫秒。当子线程处理完数据后,为了防止 UI 处理逻辑的混乱,Android 只允许主线程修改 UI,那么这时候就需要 Handler来充当子线程和主线程之间的桥梁了。
我们通常将 Handler 声明在 Activity 中,然后覆写 Handler 中的 handleMessage 方法,当子线程调用 handler.sendMessage()方法后 handleMessage 方法就会在主线程中执行。这里面除了 Handler、Message 外还有隐藏的 Looper 和 MessageQueue 对象。在主线程中 Android 默认已经调用了 Looper.preper()方法,调用该方法的目的是在 Looper 中创 建 MessageQueue 成 员 变 量 并 把 Looper对象绑定到当前线程中。 当调用 Handler 的sendMessage(对象)方法的时候就将 Message 对象添加到了 Looper 创建的 MessageQueue队列中,同时给 Message 指定了 target 对象,其实这个 target 对象就是 Handler 对象。主线程默
认执行了 Looper.looper () 方法, 该方法从 Looper 的成员变量 MessageQueue 中取出 Message,然后调用 Message 的 target 对象的 handleMessage()方法。这样就完成了整个消息机制。

2、事件分发机制

2.1 事件分发中的 onTouch 和 onTouchEvent 有什么区别,又该如何使用?
这两个方法都是在 View 的 dispatchTouchEvent 中调用的,onTouch 优先于 onTouchEvent执行。如果在 onTouch 方法中通过返回 true 将事件消费掉,onTouchEvent 将不会再执行。另外需要注意的是,onTouch 能够得到执行需要两个前提条件,第一 mOnTouchListener 的值不能为空,第二当前点击的控件必须是 enable 的。因此如果你有一个控件是非 enable 的,那么给它注册 onTouch 事件将永远得不到执行。对于这一类控件,如果我们想要监听它的 touch 事件,就必须通过在该控件中重写 onTouchEvent 方法来实现。

2.2 请描述一下 Android 的事件分发机制

Android 的事件分发机制主要是 Touch 事件分发,有两个主角:ViewGroup 和 View。Activity的 Touch 事件事实上是调用它内部的 ViewGroup 的 Touch 事件,可以直接当成 ViewGroup 处理。View 在 ViewGroup 内, ViewGroup 也可以在其他 ViewGroup 内, 这时候把内部的 ViewGroup当成 View 来分析。
先分析 ViewGroup 的处理流程:首先得有个结构模型概念:ViewGroup 和 View 组成了一棵树形结构,最顶层为 Activity 的 ViewGroup,下面有若干的 ViewGroup 节点,每个节点之下又有若干的 ViewGroup 节点或者 View 节点,依次类推。如图:

Android面试题--事件处理_第1张图片

 

当一个 Touch 事件(触摸事件为例)到达根节点,即 Acitivty 的 ViewGroup 时,它会依次下发,下发的过程是调用子 View(ViewGroup)的 dispatchTouchEvent 方法实现的。简单来说,就是ViewGroup 遍历它包含着的子 View,调用每个 View 的 dispatchTouchEvent 方法,而当子 View为 ViewGroup 时,又会通过调用 ViwGroup 的 dispatchTouchEvent 方法继续调用其内部的 View的 dispatchTouchEvent 方法。上述例子中的消息下发顺序是这样的:①-②-⑤-⑥-⑦-③-④。
dispatchTouchEvent 方法只负责事件的分发,它拥有 boolean 类型的返回值,当返回为 true 时,顺序下发会中断。在上述例子中如果⑤的dispatchTouchEvent 返回结果为 true,那么⑥-⑦-③-④将都接收不到本次 Touch 事件。

1.Touch 事 件 分 发 中 只 有 两 个 主 角 :ViewGroup 和 View。ViewGroup 包 含onInterceptTouchEvent 、 dispatchTouchEvent、onTouchEvent 三个相关事件。 View包含dispatchTouchEvent、onTouchEvent 两个相关事件。其中 ViewGroup 又继承于 View。

2.ViewGroup 和 View 组成了一个树状结构,根节点为 Activity 内部包含的一个 ViwGroup。

3.触摸事件由 Action_Down、Action_Move、Aciton_UP 组成,其中一次完整的触摸事件中,Down 和 Up 都只有一个,Move 有若干个,可以为 0 个。

4.当 Acitivty 接收到 Touch 事件时,将遍历子 View 进行 Down 事件的分发。ViewGroup 的遍历可以看成是递归的。分发的目的是为了找到真正要处理本次完整触摸事件的 View,这个 View 会在 onTouchuEvent 结果返回 true。

5.当某个子 View 返回 true 时, 会中止 Down 事件的分发, 同时在 ViewGroup 中记录该子 View。接下去的 Move 和 Up 事件将由该子 View 直接进行处理。 由于子 View 是保存在 ViewGroup 中的,多层 ViewGroup 的节点结构时,上级 ViewGroup 保存的会是真实处理事件的 View 所在的ViewGroup 对象:如 ViewGroup0-ViewGroup1-TextView 的结构中,TextView 返回了 true,它将被保存在 ViewGroup1 中,而 ViewGroup1 也会返回 true,被保存在ViewGroup0 中。当 Move和 UP 事件来时,会先从 ViewGroup0 传递至 ViewGroup1,再由 ViewGroup1 传递至 TextView。

6.当 ViewGroup 中所有子 View 都不捕获 Down 事件时,将触发 ViewGroup 自身的 onTouch事件。触发的方式是调用 super.dispatchTouchEvent 函数,即父类 View 的 dispatchTouchEvent方法。在所有子 View 都不处理的情况下,触发 Acitivity 的 onTouchEvent 方法。
7.onInterceptTouchEvent 有两个作用:1.拦截 Down 事件的分发。2.中止 Up 和 Move 事件向目标 View 传递,使得目标 View 所在的 ViewGroup 捕获 Up 和 Move 事件。

3、子线程发消息到主线程进行更新 UI,除了 handler 和 AsyncTask,还有什么?

(1)用 Activity 对象的 runOnUiThread 方法更新在子线程中通过 runOnUiThread()方法更新 UI:

(2)用 View.post(Runnable r)方法更新 UI

4、子线程中能不能 new handler?为什么?

不能,如果在子线程中直接 new Handler()会抛出异常 java.lang.RuntimeException: Can't create handler inside thread that has not called

 

你可能感兴趣的:(Android面试题--事件处理)