前语
今日在电脑上翻出了好久之前收拾笔记Framework源码面试,Flutter,以及一部分面试专题。拿出来温习一下。
关注大众号:Android苦做舟
今日先讲Framework源码篇:
1.
Framework源码面试:Activity发动流程2.
Framework源码面试:Binder面试3.
Framework源码面试:Handler面试4.
Framework源码面试:事情分发机制5.
Framework源码面试:onMeasure丈量原理6.
Framework源码面试:Android屏幕改写机制
在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 的作用
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() { @Override public void onClick(View v) { } }); -
内部类:
view.setOnClickListener(new MyClickListener()); class MyClickListener implements View.OnClickListener { @Override public void onClick(View v) { } } -
外部类:
view.setOnClickListener(new MyClickListener()); public class MyClickListener implements View.OnClickListener { @Override public void onClick(View v) { } } -
Activity完成
OnClickLister接口的办法public class TestViewActivity extends AppCompatActivity implements View.OnClickListener { MyView view; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test_view); view = (MyView) findViewById(R.id.view); view.setOnClickListener(this); } @Override public void onClick(View v) { } } -
在xml中绑定的办法:
public class TestViewActivity extends AppCompatActivity{ MyView view; @Override protected 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.MyView android: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 {
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.i("--------","MyView onTouchEvent "+MyAction.getActionType(event));
return super.onTouchEvent(event);
}
}
监听:
yelloe.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
Log.i("--------", "touch yelloe " + MyAction.getActionType(motionEvent));
return false;
}
});
yelloe.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.i("--------", "click yelloe ");
}
});
输出成果: 插图 优先级凹凸
优先级凹凸:
onTouchListener >>> onTouchEvent >>> setOnLongClickListener >>> OnClickListerner
1.3.3、如图有三個嵌套的控件,结构如下,其中黄色部分是一个继承于View的控件,绿色和红色都是继承于LinearLayout的控件: 插图:
代码简单如下:
public class MyView extends View {
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.i("--------","MyView onTouchEvent "+MyAction.getActionType(event));
return super.onTouchEvent(event);
}
}
public class MyLinearLayoutRed extends LinearLayout {
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.i("--------","MyLinearLayoutRed onTouchEvent "+MyAction.getActionType(event));
return super.onTouchEvent(event);
}
}
public class MyLinearLayoutGreen extends LinearLayout {
@Override
public 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.MyLinearLayoutRed
android:id="@+id/red"
android:layout_width="300dip"
android:layout_height="300dip"
android:background="@color/red">
<com.example.administrator.myviewevent.MyLinearLayoutGreen
android:id="@+id/green"
android:layout_width="200dip"
android:layout_height="200dip"
android:background="@color/green">
<com.example.administrator.myviewevent.MyView
android: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() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
Log.i("--------", "touch yelloe " + MyAction.getActionType(motionEvent));
return false;
}
});
green.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
Log.i("--------", "touch green " + MyAction.getActionType(motionEvent));
return false;
}
});
red.setOnTouchListener(new View.OnTouchListener() {
@Override
public 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苦做舟








