前语

今日在电脑上翻出了好久之前收拾笔记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或许拿源码剖析,然后一堆的注释和阐明,假设用心的去看肯定是收成不少可是的确很难把整个流程说清和记住。曾经也是拼命想记住整个流程,可是一段时间又忘了,终究觉得剖析这种问题和事情流的走向,一张图来解释和阐明会明晰许多,下面我根据画的一张事情分发流程图,阐明的事情从用户点击之后,在不同函数不同回来值的状况的终究走向。

Framework源码面试六部曲:4.事件分发机制

注:

  • 仔细看的话,图分为3层,从上往下依次是ActivityViewGroupView

  • 事情从左上角那个白色箭头开端,由ActivitydispatchTouchEvent做分发

  • 箭头的上面字代表办法回来值,(return truereturn falsereturn super.xxxxx(),super 的意思是调用父类完成。

  • dispatchTouchEventonTouchEvent的框里有个**【true—->消费】**的字,表明的意思是假设办法回来true,那么代表事情就此消费,不会持续往别的当地传了,事情中止。

  • 现在一切的图的事情是针对ACTION_DOWN的,关于ACTION_MOVE和ACTION_UP咱们终究做剖析。

  • 之前图中的ActivitydispatchTouchEvent 有误(图已修正),只要return super.dispatchTouchEvent(ev) 才是往下走,回来true 或许 false 事情就被消费了(中止传递)。

仔细看整个图,咱们得出事情流 走向的几个结论(期望读者专注的看下图 1,多看几遍,脑子有比较明晰的概念。) 1、假设事情不被中止,整个事情流向是一个类U型图,咱们来看下这张图,或许更能了解U型图的意思。

Framework源码面试六部曲:4.事件分发机制

所以假设咱们没有对控件里面的办法进行重写或更改回来值,而直接用super调用父类的默许完成,那么整个事情流向应该是从Activity---->ViewGroup—>View 从上往下调用dispatchTouchEvent办法,一直到叶子节点(View)的时分,再由View—>ViewGroup—>Activity从下往上调用onTouchEvent办法。

2、dispatchTouchEventonTouchEvent 一旦return true,事情就中止传递了(到达终点)(没有谁能再收到这个事情)。看下图中只要return true事情就没再持续传下去了,关于return true咱们常常说事情被消费了,消费了的意思便是事情走到这儿便是终点,不会往下传,没有谁能再收到这个事情了。

Framework源码面试六部曲:4.事件分发机制

3、dispatchTouchEventonTouchEvent return false的时分事情都回传给父控件的onTouchEvent处理。

Framework源码面试六部曲:4.事件分发机制

看上图深蓝色的线,关于回来false的状况,事情都是传给父控件onTouchEvent处理。

  • 关于dispatchTouchEvent 回来 false 的含义应该是:事情中止往子View传递和分发一起开端往父控件回溯(父控件的onTouchEvent开端从下往上回传直到某个onTouchEvent return true),事情分发机制就像递归,return false 的含义便是递归中止然后开端回溯。
  • 关于onTouchEvent return false 就比较简单了,它便是不用费事情,并让事情持续往父控件的方向从下往上流动。

4、dispatchTouchEvent、onTouchEvent、onInterceptTouchEvent ViewGroupView的这些办法的默许完成便是会让整个事情装置U型完好走完,所以 return super.xxxxxx() 就会让事情依照U型的方向的完好走完好个事情流动路径),中心不做任何改动,不回溯、不中止,每个环节都走到。

Framework源码面试六部曲:4.事件分发机制

所以假设看到办法return super.xxxxx() 那么事情的下一个流向便是走U型下一个目标,稍微记住上面这张图,你就能很快判别出下一个走向是哪个控件的哪个函数。

5、onInterceptTouchEvent 的作用

Framework源码面试六部曲:4.事件分发机制

Intercept 的意思就阻拦,每个ViewGroup每次在做分发的时分,问一问阻拦器要不要阻拦(也便是问问自己这个事情要不要自己来处理)假设要自己处理那就在onInterceptTouchEvent办法中 return true就会交给自己的onTouchEvent的处理,假设不阻拦便是持续往子控件往下传。**默许是不会去阻拦的,由于子View也需要这个事情,所以onInterceptTouchEvent阻拦器return super.onInterceptTouchEvent()return false是相同的,是不会阻拦的,事情会持续往子ViewdispatchTouchEvent传递。

6、ViewGroupViewdispatchTouchEvent办法回来super.dispatchTouchEvent()的时分事情流走向。

Framework源码面试六部曲:4.事件分发机制

首要看下ViewGroupdispatchTouchEvent,之前说的return true是完结传递。return false 是回溯到父View的onTouchEvent

然后ViewGroup怎样经过dispatchTouchEvent办法能把事情分发到自己的onTouchEvent处理呢,return truefalse 都不可,那么只能经过Interceptor把事情阻拦下来给自己的onTouchEvent,所以ViewGroup dispatchTouchEvent办法的super默许完成便是去调用onInterceptTouchEvent

记住这一点。

那么关于ViewdispatchTouchEvent 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的事情分发涉及到哪些进程和办法?

Framework源码面试六部曲:4.事件分发机制

  1. public boolean dispatchTouchEvent(MotionEvent ev) 是事情分发机制中的核心,一切的事情调度都归它管 用来进行事情的分发,假设事情能够传递给当时View,那么此办法必定会被调用
  2. public boolean onInterceptTouchEvent(MotionEvent ev)dispatchTouchEvent中调用,用来判别是否阻拦某个事情,回来成果表明是否阻拦当时事情
  3. 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;
}
  1. 关于一个ViewGroup来说,点击事情发生后,首要会传递给它,这时她的dispatchTouchEvent会被调用,假设这个ViewGroup的onInterceptTouchEvent
  2. 办法回来true表明它要阻拦当时事情,接着事情就会交给这个ViewGroup处理,即它的onTouchEvent就会被调用;假设这个这个ViewGroup的onInterceptTouchEvent
  3. 办法回来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、基于监听的事情分发有哪些?怎么来设置监听?

咱们常用的setOnClickListenerOnLongClickListenersetOnTouchListener等都是基于监听的事情处理。 设置监听能够用如下几种办法:

  1. 匿名内部类:

     view.setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View v) {
         }
     });
    
  2. 内部类:

     view.setOnClickListener(new MyClickListener());
        class MyClickListener implements View.OnClickListener
        {
            @Override
           public void onClick(View v) {
          }
        }
    
  3. 外部类:

     view.setOnClickListener(new MyClickListener());
     public class MyClickListener implements View.OnClickListener {
        @Override
         public void onClick(View v) {
        }
     }
    
  4. 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) {
       }
     }
    
  5. 在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输出的成果是什么?

答:

  1. I/——–: MyView onTouchEvent ACTION_DOWN…
  2. I/——–: MyLinearLayoutGreen onTouchEvent ACTION_DOWN…
  3. 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表明事情被耗费掉了,不会持续传递了,此时获取不到到OnClickonLongClick事情;onTouch办法回来false表明事情没有被耗费,能够持续传递,此时,能够获取到OnClickonLongClick事情; 同理 onTouchEventsetOnLongClickListener 办法中的回来值表明的含义相同;

1.3.5、setOnLongClickListener的onLongClick的回来值表明什么?

回来false,长按的话会一起履行onLongClickonClick;假设setOnLongClickListener回来true,表明事情被耗费,不会持续传递,只履行longClick

1.3.6、onTouch和onTouchEvent的异同?
  • onTouch办法是View的 OnTouchListener接口中界说的办法。当一个View绑定了OnTouchLister后,当有touch事情触发时,就会调用onTouch办法。(当把手放到View上后,onTouch办法被一遍一遍地被调用)
  • onTouchEvent办法是overrideActivity的办法。重新了ActivityonTouchEvent办法后,当屏幕有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回来值?

不影响,只要clickablelongClickable有一个为真,那么onTouchEvent就回来true。

关注大众号:Android苦做舟