Framework源码面试——Handler与事件传递机制面试集合
Handler面试题
Handler的作用:
当我们需要在子线程处理耗时的操作(例如访问网络,数据库的操作),而当耗时的操作完成后,需要更新UI,这就需要使用Handler来处理,因为子线程不能做更新UI的操作。Handler能帮我们很容易的把任务(在子线程处理)切换回它所在的线程。简单理解,Handler就是解决线程和线程之间的通信的。
1.Handler连环之说说Handler的作用,以及每个类让他们的角色
使用的handler的两种形式
1.在主线程使用handler;
2.在子线程使用handler。
Handler的消息处理主要有五个部分组成
- Message
- Handler
- Message Queue
- Looper
- ThreadLocal
首先简要的了解这些对象的概念
- Message:Message是在线程之间传递的消息,它可以在内部携带少量的数据,用于线程之间交换数据。Message有四个常用的字段,what字段,arg1字段,arg2字段,obj字段。what,arg1,arg2可以携带整型数据,obj可以携带object对象。
- Handler:它主要用于发送和处理消息的发送消息一般使用
sendMessage()方法,还有其他的一系列sendXXX的方法,但最终都是调用了sendMessageAtTime方法,除了sendMessageAtFrontOfQueue()这个方法 而发出的消息经过一系列的辗转处理后,最终会传递到Handler的handleMessage方法中。 - Message Queue:
MessageQueue是消息队列的意思,它主要用于存放所有通过Handler发送的消息,这部分的消息会一直存在于消息队列中,等待被处理。每个线程中只会有一个MessageQueue对象。 - Looper:每个线程通过Handler发送的消息都保存在,
MessageQueue中,Looper通过调用loop()的方法,就会进入到一个无限循环当中,然后每当发现Message Queue中存在一条消息,就会将它取出,并传递到Handler的handleMessage()方法中。每个线程中只会有一个Looper对象。
ThreadLocal:MessageQueue对象,和Looper对象在每个线程中都只会有一个对象,怎么能保证它只有一个对象,就通过ThreadLocal来保存。Thread Local是一个线程内部的数据存储类,通过它可以在指定线程中存储数据,数据存储以后,只有在指定线程中可以获取到存储到数据,对于其他线程来说则无法获取到数据。
2.Handler连环泡之 说说 Looper 死循环为什么不会导致应用卡死?
线程默认没有
Looper的,如果需要使用Handler就必须为线程创建Looper。我们经常提到的主线程,也叫UI线程,它就是ActivityThread,ActivityThread被创建时就会初始化Looper,这也是在主线程中默认可以使用Handler的原因。
首先我们看一段代码
new Thread(new Runnable() {@Overridepublic void run() {Log.e("qdx", "step 0 ");Looper.prepare();Toast.makeText(MainActivity.this, "run on Thread", Toast.LENGTH_SHORT).show();Log.e("qdx", "step 1 ");Looper.loop();Log.e("qdx", "step 2 ");}}).start();
我们知道Looper.loop();里面维护了一个死循环方法,所以按照理论,上述代码执行的应该是 step 0 –>step 1 也就是说循环在Looper.prepare();与Looper.loop();之间。
在子线程中,如果手动为其创建了
Looper,那么在所有的事情完成以后应该调用quit方法来终止消息循环,否则这个子线程就会一直处于等待(阻塞)状态,而如果退出Looper以后,这个线程就会立刻(执行所有方法并)终止,因此建议不需要的时候终止Looper。
执行结果也正如我们所说,这时候如果了解了ActivityThread,并且在main方法中我们会看到主线程也是通过Looper方式来维持一个消息循环
public static void main(String[] args) {Looper.prepareMainLooper();//创建Looper和MessageQueue对象,用于处理主线程的消息ActivityThread thread = new ActivityThread();thread.attach(false);//建立Binder通道 (创建新线程)if (sMainThreadHandler == null) {sMainThreadHandler = thread.getHandler();}Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);Looper.loop();//如果能执行下面方法,说明应用崩溃或者是退出了...throw new RuntimeException("Main thread loop unexpectedly exited");}
那么回到我们的问题上,这个死循环会不会导致应用卡死,即使不会的话,它会慢慢的消耗越来越多的资源吗?
对于线程即是一段可执行的代码,当可执行代码执行完成后,线程生命周期便该终止了,线程退出。而对于主线程,我们是绝不希望会被运行一段时间,自己就退出,那么如何保证能一直存活呢?简单做法就是可执行代码是能一直执行下去的,死循环便能保证不会被退出,例如,binder线程也是采用死循环的方法,通过循环方式不同与Binder驱动进行读写操作,当然并非简单地死循环,无消息时会休眠。但这里可能又引发了另一个问题,既然是死循环又如何去处理其他事务呢?通过创建新线程的方式。真正会卡死主线程的操作是在回调方法
onCreate/onStart/onResume等操作时间过长,会导致掉帧,甚至发生ANR,looper.loop本身不会导致应用卡死。
主线程的死循环一直运行是不是特别消耗CPU资源呢? 其实不然,这里就涉及到
Linux pipe/epoll机制,简单说就是在主线程的MessageQueue没有消息时,便阻塞在loop的queue.next()中的nativePollOnce()方法里,此时主线程会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生,通过往pipe管道写端写入数据来唤醒主线程工作。这里采用的epoll机制,是一种IO多路复用机制,可以同时监控多个描述符,当某个描述符就绪(读或写就绪),则立刻通知相应程序进行读或写操作,本质同步I/O,即读写是阻塞的。 所以说,主线程大多数时候都是处于休眠状态,并不会消耗大量CPU资源。 Gityuan–Handler(Native层)
3.Handler连环泡之 说说 Looper 死循环为什么不会导致应用卡死?
事实上,会在进入死循环之前便创建了新binder线程,在代码
ActivityThread.main()中:
public static void main(String[] args) {
//创建Looper和MessageQueue对象,用于处理主线程的消息Looper.prepareMainLooper();//创建ActivityThread对象ActivityThread thread = new ActivityThread(); //建立Binder通道 (创建新线程)thread.attach(false);Looper.loop(); //消息循环运行throw new RuntimeException("Main thread loop unexpectedly exited");
}
Activity的生命周期都是依靠主线程的Looper.loop,当收到不同Message时则采用相应措施:一旦退出消息循环,那么你的程序也就可以退出了。 从消息队列中取消息可能会阻塞,取到消息会做出相应的处理。如果某个消息处理时间过长,就可能会影响UI线程的刷新速率,造成卡顿的现象。
thread.attach(false)方法函数中便会创建一个Binder线程(具体是指ApplicationThread,Binder的服务端,用于接收系统服务AMS发送来的事件),该Binder线程通过Handler将Message发送给主线程。「Activity 启动过程」
比如收到msg=H.LAUNCH_ACTIVITY,则调用ActivityThread.handleLaunchActivity()方法,最终会通过反射机制,创建Activity实例,然后再执行Activity.onCreate()等方法;
再比如收到msg=H.PAUSE_ACTIVITY,则调用ActivityThread.handlePauseActivity()方法,最终会执行Activity.onPause()等方法。
事件传递机制
在Android开发中,事件分发机制是一块Android比较重要的知识体系,了解并熟悉整套的分发机制有助于更好的分析各种点击滑动失效问题,更好去扩展控件的事件功能和开发自定义控件,同时事件分发机制也是Android面试必问考点之一,如果你能把下面的一些事件分发图当场画出来肯定加分不少。
废话不多说,总结一句:面试时事件分发机制很重要。
1.1 Android 事件原理和 事件分发流
先弄清楚Android 事件原理后 我们再来看怎么面试
关于Android 事件分发机制网上的博文很多,但是很多都是写个Demo然后贴一下输出的Log或者拿源码分析,然后一堆的注释和说明,如果用心的去看肯定是收获不少但是确实很难把整个流程说清和记住。曾经也是拼命想记住整个流程,但是一段时间又忘了,最后觉得分析这种问题和事件流的走向,一张图来解释和说明会清晰很多,下面我根据画的一张事件分发流程图,说明的事件从用户点击之后,在不同函数不同返回值的情况的最终走向。

注:
- 仔细看的话,图分为3层,从上往下依次是
Activity、ViewGroup、View- 事件从左上角那个白色箭头开始,由
Activity的dispatchTouchEvent做分发- 箭头的上面字代表方法返回值,(
return true、return false、return super.xxxxx(),super的意思是调用父类实现。dispatchTouchEvent和onTouchEvent的框里有个**【true---->消费】**的字,表示的意思是如果方法返回true,那么代表事件就此消费,不会继续往别的地方传了,事件终止。- 目前所有的图的事件是针对
ACTION_DOWN的,对于ACTION_MOVE和ACTION_UP我们最后做分析。- 之前图中的
Activity的dispatchTouchEvent有误(图已修复),只有return super.dispatchTouchEvent(ev)才是往下走,返回true或者false事件就被消费了(终止传递)。
仔细看整个图,我们得出事件流 走向的几个结论(希望读者专心的看下图 1,多看几遍,脑子有比较清晰的概念。) 1、如果事件不被中断,整个事件流向是一个类U型图,我们来看下这张图,可能更能理解U型图的意思。

所以如果我们没有对控件里面的方法进行重写或更改返回值,而直接用super调用父类的默认实现,那么整个事件流向应该是从Activity---->ViewGroup—>View 从上往下调用dispatchTouchEvent方法,一直到叶子节点(View)的时候,再由View—>ViewGroup—>Activity从下往上调用onTouchEvent方法。
2、dispatchTouchEvent 和 onTouchEvent 一旦return true,事件就停止传递了(到达终点)(没有谁能再收到这个事件)。看下图中只要return true事件就没再继续传下去了,对于return true我们经常说事件被消费了,消费了的意思就是事件走到这里就是终点,不会往下传,没有谁能再收到这个事件了。

3、dispatchTouchEvent 和 onTouchEvent return false的时候事件都回传给父控件的onTouchEvent处理。

看上图深蓝色的线,对于返回false的情况,事件都是传给父控件onTouchEvent处理。
- 对于
dispatchTouchEvent返回false的含义应该是:事件停止往子View传递和分发同时开始往父控件回溯(父控件的onTouchEvent开始从下往上回传直到某个onTouchEvent return true),事件分发机制就像递归,return false的意义就是递归停止然后开始回溯。
- 对于
onTouchEvent return false就比较简单了,它就是不消费事件,并让事件继续往父控件的方向从下往上流动。
4、dispatchTouchEvent、onTouchEvent、onInterceptTouchEvent ViewGroup 和View的这些方法的默认实现就是会让整个事件安装U型完整走完,所以 return super.xxxxxx() 就会让事件依照U型的方向的完整走完整个事件流动路径),中间不做任何改动,不回溯、不终止,每个环节都走到。

所以如果看到方法return super.xxxxx() 那么事件的下一个流向就是走U型下一个目标,稍微记住上面这张图,你就能很快判断出下一个走向是哪个控件的哪个函数。
5、onInterceptTouchEvent 的作用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O41055AD-1678365727254)(https://upload-images.jianshu.io/upload_images/23851953-9f65a8d72ef34aa6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]
Intercept 的意思就拦截,每个ViewGroup每次在做分发的时候,问一问拦截器要不要拦截(也就是问问自己这个事件要不要自己来处理)如果要自己处理那就在onInterceptTouchEvent方法中 return true就会交给自己的onTouchEvent的处理,如果不拦截就是继续往子控件往下传。**默认是不会去拦截的,因为子View也需要这个事件,所以onInterceptTouchEvent拦截器return super.onInterceptTouchEvent()和return false是一样的,是不会拦截的,事件会继续往子View的dispatchTouchEvent传递。
6、ViewGroup 和View 的dispatchTouchEvent方法返回super.dispatchTouchEvent()的时候事件流走向。

首先看下ViewGroup 的dispatchTouchEvent,之前说的return true是终结传递。return false 是回溯到父View的onTouchEvent,
然后ViewGroup怎样通过dispatchTouchEvent方法能把事件分发到自己的onTouchEvent处理呢,return true和false 都不行,那么只能通过Interceptor把事件拦截下来给自己的onTouchEvent,所以ViewGroup dispatchTouchEvent方法的super默认实现就是去调用onInterceptTouchEvent,
记住这一点。
那么对于View的dispatchTouchEvent return super.dispatchTouchEvent()的时候呢事件会传到哪里呢,很遗憾View没有拦截器。但是同样的道理return true是终结。return false 是回溯会父类的onTouchEvent,怎样把事件分发给自己的onTouchEvent 处理呢,那只能return super.dispatchTouchEvent,View类的dispatchTouchEvent()方法默认实现就是能帮你调用View自己的onTouchEvent方法的
1.2 如何面试,以及面试官会出现什么考点
1.2.1、为什么会有事件分发机制?
我们知道,android的布局结构是树形结构,这就会导致一些View可能会重叠在一起,当我们手指点击的地方在很多个布局范围之内,也就是说此时有好多个布局可以响应我们的点击事件,这个时候该让哪个view来响应我们的点击事件呢?这就是事件分发机制存在的意义。
1.2.2、ViewGroup的事件分发涉及到哪些过程和方法?

-
public boolean dispatchTouchEvent(MotionEvent ev)是事件分发机制中的核心,所有的事件调度都归它管 用来进行事件的分发,如果事件能够传递给当前View,那么此方法一定会被调用 -
public boolean onInterceptTouchEvent(MotionEvent ev)在dispatchTouchEvent中调用,用来判断是否拦截某个事件,返回结果表示是否拦截当前事件 -
public boolean onTouchEvent(MotionEvent event)在dispatchTouchEvent中调用,用来处理点击事件,返回结果表示是否消耗当前事件
1.2.3、View中为什么会有dispatchTouchEvent方法,它存在的意义是什么?
我们知道View可以注册很多监听事件(下文有详细),比如,触摸事件,单击事件,长按事件等,而且view也有自己的onTouchEvent方法,那么这么多事件应该由谁来调度管理呢?这就是是View中dispatchTouchEvent方法存在的意义。
1.2.4、View中为什么没有onInterceptTouchEvent事件拦截方法?
View最为事件传递的最末端,要么消费掉事件,要么不处理进行回传,根本没必要进行事件拦截
1.2.5、用伪代码表示ViewGroup的事件分发过程并解释?
public boolean dispatchTouchEvent(MotionEvent ev) {boolean consume = false;if (onInterceptTouchEvent(ev)) {consume = onTouchEvent(ev);} else {consume = child.dispatchTouchEvent(ev);}return consume;
}
-
对于一个
ViewGroup来说,点击事件产生后,首先会传递给它,这时她的dispatchTouchEvent会被调用,如果这个ViewGroup的onInterceptTouchEvent -
方法返回true表示它要拦截当前事件,接着事件就会交给这个ViewGroup处理,即它的
onTouchEvent就会被调用;如果这个这个ViewGroup的onInterceptTouchEvent -
方法返回false就表示它不拦截当前事件,这时事件就会传递给子元素,接着子元素的
dispatchTouchEvent方法就会被调用,如此反复直到事件最终被处理。
1.2.6、简述事件传递的流程
- 事件都是从
Activity.dispatchTouchEvent()开始传递 - 一个事件发生后,首先传递给Activity,然后一层一层往下传,从上往下调用
dispatchTouchEvent方法传递事件:activity --> ~~ --> ViewGroup --> View - 如果事件传递给最下层的View还没有被消费,就会按照反方向回传给Activity,从下往上调用
onTouchEvent方法,最后会到Activity的onTouchEvent()函数,如果Activity也没有消费处理事件,这个事件就会被抛弃:View --> ViewGroup --> ~~ --> Activity dispatchTouchEvent方法用于事件的分发,Android中所有的事件都必须经过这个方法的分发,然后决定是自身消费当前事件还是继续往下分发给子控件处理。返回true表示不继续分发,事件没有被消费。返回false则继续往下分发,如果是ViewGroup则分发给onInterceptTouchEvent进行判断是否拦截该事件。onTouchEvent方法用于事件的处理,返回true表示消费处理当前事件,返回false则不处理,交给子控件进行继续分发。onInterceptTouchEvent是ViewGroup中才有的方法,View中没有,它的作用是负责事件的拦截,返回true的时候表示拦截当前事件,不继续往下分发,交给自身的onTouchEvent进行处理。返回false则不拦截,继续往下传。这是ViewGroup特有的方法,因为ViewGroup中可能还有子View,而在Android中View中是不能再包含子View的- 上层View既可以直接拦截该事件,自己处理,也可以先询问(分发给)子View,如果子View需要就交给子View处理,如果子View不需要还能继续交给上层View处理。既保证了事件的有序性,又非常的灵活。
- 事件由父View传递给子View,ViewGroup可以通过
onInterceptTouchEvent()方法对事件拦截,停止其向子view传递 - 如果View没有对
ACTION_DOWN进行消费,之后的其他事件不会传递过来,也就是说ACTION_DOWN必须返回true,之后的事件才会传递进来
1.2.7、ViewGroup 和 View 同时注册了事件监听器(onClick等),哪个会执行?
事件优先给View,会被View消费掉,ViewGroup 不会响应。
1.2.8、当俩个或多个View重叠时,事件该如何分配?
当 View 重叠时,一般会分配给显示在最上面的 View,也就是后加载的View。
1.2.9、dispatchTouchEvent每次都会被调用吗?
是的,onInterceptTouchEvent则不会。
1.2.10、一旦有事件传递给view,view的onTouchEvent一定会被调用吗?
View没有onInterceptTouchEvent方法,一旦有事件传递给它,他的onTouchEvent就一定会被调用。
1.2.11、ViewGroup 默认拦截事件吗?
ViewGroup默认不拦截任何事件;看源码可以知道ViewGroup的onInterceptTouchEvent方法中只有一行代码:return false;
1.2.12、事件分为几个步骤?
down事件开头,up事件结尾,中间可能会有数目不定的move事件。
1.3 View事件的优先级会考哪些内容
1.3.1、基于监听的事件分发有哪些?怎么来设置监听?
我们常用的setOnClickListener、OnLongClickListener、setOnTouchListener等都是基于监听的事件处理。 设置监听可以用如下几种方式:
- 匿名内部类:
view.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {}});
- 内部类:
view.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {}});
- 外部类:
view.setOnClickListener(new MyClickListener());public class MyClickListener implements View.OnClickListener {@Overridepublic void onClick(View v) {}}
- Activity实现
OnClickLister接口的方式
public class TestViewActivity extends AppCompatActivity implements View.OnClickListener {MyView view;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_test_view);view = (MyView) findViewById(R.id.view);view.setOnClickListener(this);}@Overridepublic void onClick(View v) {}}
- 在xml中绑定的方式:
public class TestViewActivity extends AppCompatActivity{MyView view;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_test_view);view = (MyView) findViewById(R.id.view);}public void MyClick(View view){}}<com.art.chapter_3.MyViewandroid:id="@+id/view"android:layout_width="100dip"android:layout_height="100dip"android:background="@color/colorPrimaryDark"android:onClick="MyClick"/>
1.3.2、view的onTouchEvent,OnClickListerner和OnTouchListener的onTouch方法 三者优先级如何?
代码验证:
自定义view:
public class MyView extends View {@Overridepublic boolean onTouchEvent(MotionEvent event) {Log.i("--------","MyView onTouchEvent "+MyAction.getActionType(event));return super.onTouchEvent(event);}
}
监听:
yelloe.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View view, MotionEvent motionEvent) {Log.i("--------", "touch yelloe " + MyAction.getActionType(motionEvent));return false;}});yelloe.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Log.i("--------", "click yelloe ");}});
输出结果: 插图 优先级高低
优先级高低:
onTouchListener >>> onTouchEvent >>> setOnLongClickListener >>> OnClickListerner
1.3.3、如图有三個嵌套的控件,结构如下,其中黄色部分是一个继承于View的控件,绿色和红色都是继承于LinearLayout的控件: 插图:
代码简单如下:
public class MyView extends View {@Overridepublic boolean onTouchEvent(MotionEvent event) {Log.i("--------","MyView onTouchEvent "+MyAction.getActionType(event));return super.onTouchEvent(event);}
}public class MyLinearLayoutRed extends LinearLayout {@Overridepublic boolean onTouchEvent(MotionEvent event) {Log.i("--------","MyLinearLayoutRed onTouchEvent "+MyAction.getActionType(event));return super.onTouchEvent(event);}
}public class MyLinearLayoutGreen extends LinearLayout {@Overridepublic boolean onTouchEvent(MotionEvent event) {Log.i("--------","MyLinearLayoutRed onTouchEvent "+MyAction.getActionType(event));return super.onTouchEvent(event);}
}<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><com.example.administrator.myviewevent.MyLinearLayoutRedandroid:id="@+id/red"android:layout_width="300dip"android:layout_height="300dip"android:background="@color/red"><com.example.administrator.myviewevent.MyLinearLayoutGreenandroid:id="@+id/green"android:layout_width="200dip"android:layout_height="200dip"android:background="@color/green"><com.example.administrator.myviewevent.MyViewandroid:id="@+id/yellow"android:layout_width="130dip"android:layout_height="130dip"android:background="@color/yellow" /></com.example.administrator.myviewevent.MyLinearLayoutGreen></com.example.administrator.myviewevent.MyLinearLayoutRed>
</FrameLayout>
问题一:如果不在onTouchEvent方法中做任何处理,只是Log输出每一层的Touch事件类型,现在用手指按下在黄色区域并移动后抬起.请问Log输出的结果是什么?
答:
- I/--------: MyView onTouchEvent ACTION_DOWN…
- I/--------: MyLinearLayoutGreen onTouchEvent ACTION_DOWN…
- I/--------: MyLinearLayoutRed onTouchEvent ACTION_DOWN…
问题二:如果不在onTouchEvent方法和setOnTouchListener的onTouch方法中做任何处理,只是Log输出每一层的Touch事件类型,现在用手指按下在黄色区域并移动后抬起.请问Log输出的结果是什么? 在Activity中增加setOnTouchListener监听
yelloe.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View view, MotionEvent motionEvent) {Log.i("--------", "touch yelloe " + MyAction.getActionType(motionEvent));return false;}});green.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View view, MotionEvent motionEvent) {Log.i("--------", "touch green " + MyAction.getActionType(motionEvent));return false;}});red.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View view, MotionEvent motionEvent) {Log.i("--------", "touch red " + MyAction.getActionType(motionEvent));return false;}});
答:
I/--------: touch yelloe ACTION_DOWN…
I/--------: MyView onTouchEvent ACTION_DOWN…
I/--------: touch green ACTION_DOWN… I/--------: MyLinearLayoutGreen onTouchEvent ACTION_DOWN…
I/--------: touch red ACTION_DOWN…
I/--------: MyLinearLayoutRed onTouchEvent ACTION_DOWN…
1.3.4、setOnTouchListener中onTouch的返回值表示什么意思?
onTouch方法返回true表示事件被消耗掉了,不会继续传递了,此时获取不到到OnClick和onLongClick事件;onTouch方法返回false表示事件没有被消耗,可以继续传递,此时,可以获取到OnClick和onLongClick事件; 同理 onTouchEvent 和 setOnLongClickListener方法中的返回值表示的意义一样;
1.3.5、setOnLongClickListener的onLongClick的返回值表示什么?
返回false,长按的话会同时执行onLongClick和onClick;如果setOnLongClickListener返回true,表示事件被消耗,不会继续传递,只执行longClick;
1.3.6、onTouch和onTouchEvent的异同?
-
onTouch方法是View的OnTouchListener接口中定义的方法。当一个View绑定了OnTouchLister后,当有touch事件触发时,就会调用onTouch方法。(当把手放到View上后,onTouch方法被一遍一遍地被调用) -
onTouchEvent方法是override的Activity的方法。重新了Activity的onTouchEvent方法后,当屏幕有touch事件时,此方法就会被调用。 -
onTouch优先于onTouchEvent执行,如果在onTouch方法中通过返回true将事件消费掉,onTouchEvent将不会再执行。 -
相同点是它们都是在在View的dispatchTouchEvent中调用的;
1.3.7、点击事件的传递过程?
Activity-Window-View。 从上到下依次传递,当然了如果你最低的那个view onTouchEvent返回false 那就说明他不想处理 那就再往上抛,都不处理的话最终就还是让Activity自己处理了。
1.3.8、如果某个view 处理事件的时候 没有消耗down事件 会有什么结果?
假如一个view,在down事件来的时候 他的onTouchEvent返回false, 那么这个down事件 所属的事件序列 就是他后续的move 和up 都不会给他处理了,全部都给他的父view处理。
1.3.9、如果view 不消耗move或者up事件 会有什么结果?
那这个事件所属的事件序列就消失了,父view也不会处理的,最终都给activity 去处理了。
1.3.10、enable是否影响view的onTouchEvent返回值?
不影响,只要clickable和longClickable有一个为真,那么onTouchEvent就返回true。
Android 面试题锦:https://qr18.cn/CKV8OZ
相关文章:
Framework源码面试——Handler与事件传递机制面试集合
Handler面试题 Handler的作用: 当我们需要在子线程处理耗时的操作(例如访问网络,数据库的操作),而当耗时的操作完成后,需要更新UI,这就需要使用Handler来处理,因为子线程不能做更新…...
iOS开发-bugly符号表自动上传发布自动化shell
这里介绍的是通过build得到的app文件和dSYM文件来打包分发和符号表上传。 通过Archive方式打包和获得符号表的方式以后再说。 一:bugly工具jar包准备 bugly符号表工具下载地址:(下载完成后放入项目目录下,如不想加入git可通过gitIgnore忽略…...
MySQL OCP888题解046-哪些语句会被记录到binlog
文章目录1、原题1.1、英文原题1.2、中文翻译1.3、答案2、题目解析2.1、题干解析2.2、选项解析3、知识点3.1、知识点1:binlog_format选项3.2、知识点2:Performance Schema(性能模式)4、总结1、原题 1.1、英文原题 You enable binary logging on MySQL S…...
【前端学习】D5:CSS进阶
文章目录前言系列文章目录1 精灵图Sprites1.1 为什么需要精灵图?1.2 精灵图的使用2 字体图标iconfont2.1 字体图标的产生2.2 字体图标的优点2.3 字体文件格式2.4 字体图标的使用2.5 字体图标的引入2.6 字体图标的追加3 CSS三角3.1 普通三角3.2 案例4 CSS用户界面样式…...
【bioinfo】融合检测软件FusionMap分析流程和报告结果
文章目录写在前面FusionMap融合检测原理FusionMap与其他软比较FusionMap分析流程FusionMap结果文件说明FusionMap mono CUP设置图片来源: https://en.wikipedia.org/wiki/Fusion_gene写在前面 下面主要内容是关于RNA-seq数据分析融合,用到软件是FusionMap 【Fusion…...
C++基础了解-17-C++日期 时间
C日期 & 时间 一、C日期 & 时间 C 标准库没有提供所谓的日期类型。C 继承了 C 语言用于日期和时间操作的结构和函数。为了使用日期和时间相关的函数和结构,需要在 C 程序中引用 头文件。 有四个与时间相关的类型:clock_t、time_t、size_t 和 …...
MOV压敏电阻的几种电路元件功能及不同优势讲解
压敏电阻,通常是电路为防护浪涌冲击电压而使用的一种电子元器件,相比其他的浪涌保护器来说,也有那么几个不一样的优势,那么,具体有哪些?以及关于它的作用,你都知道吗?以下优恩小编为…...
uniapp+uniCloud实战项目报修小程序开发
前言 本项目基于 uniapp uniCloud 云开发,简单易用,逻辑主要是云数据库的增删查改,页面大部分自写,部分使用uniUI, uView 组件库。大家可用于学习或者二次开发,有什么不懂的地方可联系 wechat:MrYe443。用…...
演唱会的火车票没了?Python实现12306查票以及zidong购票....
嗨害大家好!我是小熊猫~ 不知道大家抢到演唱会的门票没有呢? 不管抢到没有,火车票也是很重要的哇 24小时抢票不间断的那种喔~ ~ ~ 不然可就要走路去了喔~ 准备工作 环境 Python 3.8Pycharm 插件 谷歌浏览器驱动 模块 需要安装的第三方模块&am…...
Linux发行版本与发行版的简单的介绍
Linux linux下有很多发行的版本,或者称之为魔改版本。以下介绍一些常见的版本,以避免名词的混淆。 linux是提供了一个内核,就像是谷歌的内核一样,QQ浏览器就是使用的谷歌的内核,也算是一个发行版本。 Ubuntu&#x…...
前后端分离项目学习-vue+springboot 博客
前后端分离项目 文章总体分为2大部分,Java后端接口和vue前端页面 项目演示:www.markerhub.com:8084/blogs Java后端接口开发 1、前言 从零开始搭建一个项目骨架,最好选择合适,熟悉的技术,并且在未来易拓展…...
关于指针运算的一道题
目录 刚看到这道题的时候我也和大多数小白一样感到无从下手,但是在我写这篇博客的前几分钟开始我对这道题有了一点点的理解。所以我就想着趁热打铁,写一篇博客来记录一下我的想法。 题目如下: 画图: 逐一解答: 题一…...
【论文简述】Learning Optical Flow with Kernel Patch Attention(CVPR 2022)
一、论文简述 1. 第一作者:Ao Luo 2. 发表年份:2022 3. 发表期刊:CVPR 4. 关键词:光流、局部注意力、空间关联、上下文关联 5. 探索动机:现有方法主要将光流估计视为特征匹配任务,即学习在特征空间中将…...
Java学习-MySQL-列的数据类型
Java学习-MySQL-列的数据类型 数值 tinyint - 1个字节smallint - 2个字节mediumint - 3个字节int - 4个字节bigint - 8个字节float - 4个字节double - 8个字节decimal - 字符串形式的浮点数 字符串 char - 0~255varchar - 可变字符串 0~65535tinytext - 微型文本 2^8-1text…...
终端配色-Docker容器终端
20230309 - 0. 引言 平时使用SSH,通常都是使用securecrt来用,毕竟也算是之前windows下一种使用的工具,在mac下使用还算方便;进入终端后,可以通过调整配色来调整编程环境。平时经常使用屎黄色的那种配色,毕…...
SQL基础培训04-插入数据
知识点: 假设有订单表 CREATE TABLE SEOrder ( FID int identity(...
Apache HTTP Server <2.4.56 mod_proxy 模块存在请求走私漏洞(CVE-2023-25690)
漏洞描述 Apache HTTP Server是一款Web服务器。 该项目受影响版本存在请求走私漏洞。由于intro.xml中存在RewriteRule配置不当,当Apache启用mod_proxy且配置如 RewriteRule “^/here/(.*)” " http://example.com:8080/elsewhere?$1"; http://example.…...
SpringBoot 集成 elasticsearch 7.x和对应版本不一致异常信息处理
开源框架springboot框架中集成es。使用org.springframework.data.elasticsearch下的依赖,实现对elasticsearch的CURD,非常方便,但是springboot和elasticsearch版本对应很严格,对应版本不统一启动会报错。 文章目录开源框架Elasticsearch 7.x安装Elastics…...
求职季必看系列:Java如何高效面试?
先看看这些java高频的面试重点吧 以下是初级程序员面试经常问到的问题: ■ Spring的三大特性是什么? ■ Spring IOC和AOP 你是如何理解并且使用的? ■ 说一下ElasticSearch为什么查询的快?是如何存储的?在项目中…...
点云分割预研
文章目录激光雷达点云分割1.点云分割主流方案(模型角度)1.1 (a) 基于RGB-D图像1.2 (d) 基于点云1.3 (b) 基于投影图像1.4 (b) 基于投影图像 - SqueezeSeg/RangeNet1.4. 球映射2 点云分割主流方案(部署角度)3 点云分割常用指标4 点…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...
处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...
MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...
mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...
