Framework源码面试——Handler与事件传递机制面试集合

news2024/11/14 21:40:12

Handler面试题

Handler的作用:
当我们需要在子线程处理耗时的操作(例如访问网络,数据库的操作),而当耗时的操作完成后,需要更新UI,这就需要使用Handler来处理,因为子线程不能做更新UI的操作。Handler能帮我们很容易的把任务(在子线程处理)切换回它所在的线程。简单理解,Handler就是解决线程和线程之间的通信的。

1.Handler连环之说说Handler的作用,以及每个类让他们的角色

使用的handler的两种形式

1.在主线程使用handler;
2.在子线程使用handler。

Handler的消息处理主要有五个部分组成

  • Message
  • Handler
  • Message Queue
  • Looper
  • ThreadLocal

首先简要的了解这些对象的概念

  1. Message:Message是在线程之间传递的消息,它可以在内部携带少量的数据,用于线程之间交换数据。Message有四个常用的字段,what字段,arg1字段,arg2字段,obj字段。what,arg1,arg2可以携带整型数据,obj可以携带object对象。
  2. Handler:它主要用于发送和处理消息的发送消息一般使用sendMessage()方法,还有其他的一系列sendXXX的方法,但最终都是调用了sendMessageAtTime方法,除了sendMessageAtFrontOfQueue()这个方法 而发出的消息经过一系列的辗转处理后,最终会传递到Handler的handleMessage方法中。
  3. Message QueueMessageQueue是消息队列的意思,它主要用于存放所有通过Handler发送的消息,这部分的消息会一直存在于消息队列中,等待被处理。每个线程中只会有一个MessageQueue对象。
  4. Looper:每个线程通过Handler发送的消息都保存在,MessageQueue中,Looper通过调用loop()的方法,就会进入到一个无限循环当中,然后每当发现Message Queue中存在一条消息,就会将它取出,并传递到Handler的handleMessage()方法中。每个线程中只会有一个Looper对象。

ThreadLocalMessageQueue对象,和Looper对象在每个线程中都只会有一个对象,怎么能保证它只有一个对象,就通过ThreadLocal来保存。Thread Local是一个线程内部的数据存储类,通过它可以在指定线程中存储数据,数据存储以后,只有在指定线程中可以获取到存储到数据,对于其他线程来说则无法获取到数据。

2.Handler连环泡之 说说 Looper 死循环为什么不会导致应用卡死?

线程默认没有Looper的,如果需要使用Handler就必须为线程创建Looper。我们经常提到的主线程,也叫UI线程,它就是ActivityThreadActivityThread被创建时就会初始化Looper,这也是在主线程中默认可以使用Handler的原因。

首先我们看一段代码

 new Thread(new Runnable() {
        @Override
        public 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没有消息时,便阻塞在loopqueue.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层,从上往下依次是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型图的意思。

所以如果我们没有对控件里面的方法进行重写或更改返回值,而直接用super调用父类的默认实现,那么整个事件流向应该是从Activity---->ViewGroup—>View 从上往下调用dispatchTouchEvent方法,一直到叶子节点(View)的时候,再由View—>ViewGroup—>Activity从下往上调用onTouchEvent方法。

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

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

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

  • 对于dispatchTouchEvent 返回 false 的含义应该是:事件停止往子View传递和分发同时开始往父控件回溯(父控件的onTouchEvent开始从下往上回传直到某个onTouchEvent return true),事件分发机制就像递归,return false 的意义就是递归停止然后开始回溯。
  • 对于onTouchEvent return false 就比较简单了,它就是不消费事件,并让事件继续往父控件的方向从下往上流动。

4、dispatchTouchEvent、onTouchEvent、onInterceptTouchEvent ViewGroupView的这些方法的默认实现就是会让整个事件安装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是一样的,是不会拦截的,事件会继续往子ViewdispatchTouchEvent传递。

6、ViewGroupViewdispatchTouchEvent方法返回super.dispatchTouchEvent()的时候事件流走向。

首先看下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的事件分发涉及到哪些过程和方法?

  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) {

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

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

    }
 }
  1. 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) {
   }
 }
  1. 在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 面试题锦:https://qr18.cn/CKV8OZ

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/400256.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

软件回归测试是什么?

一、软件回归测试是什么? 软件回归测试作为软件生命周期的一个组成部分&#xff0c;在整个软件测试过程中占有很大的工作量比重&#xff0c;软件开发的各个阶段都会进行多次回归测试。回归测试是指修改了旧代码后&#xff0c;重新进行测试以确认修改没有引入新的错误或导致其…

Boosting三巨头:XGBoost、LightGBM和CatBoost(发展、原理、区别和联系,附代码和案例)

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️&#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

Binder ——binder的jni注册和binder驱动

环境&#xff1a;Android 11源码Android 11 内核源码源码阅读器 sublime textbinder的jni方法注册zygote启动1-1、启动zygote进程zygote是由init进程通过解析init.zygote.rc文件而创建的&#xff0c;zygote所对应的可执行程序是app_process&#xff0c;所对应的源文件是app_mai…

因果推断12--dragonnet论文和代码学习

目录 论文 dragonnet 1介绍 2 Dragonnet 3定向正则化 4相关工作 5实验 6讨论 NN-Based的模型 dragonnet 如何更新参数 dragonnet的损失函数 CausalML Dragonnet类 论文代码 论文 dragonnet Adapting Neural Networks for the Estimation of Treatment Effects 应…

二叉搜索树的实现

什么是二叉搜索树1.若它的左子树不为空&#xff0c;那么左子树上所有节点都小于根节点2.若它的右子树不为空&#xff0c;那么右子树上所有节点都小于根节点3.它的左右子树也分别是二叉搜索树4.使用中序遍历结果是从小到大定义节点&#xff0c;使用静态内部类static class TreeN…

http组成及状态及参数传递

http组成及状态及参数传递 早期的网页都是通过后端渲染来完成的&#xff1a;服务器端渲染&#xff08;SSR&#xff0c;server side render&#xff09;&#xff1a; 客户端发出请求 -> 服务端接收请求并返回相应HTML文档 -> 页面刷新&#xff0c;客户端加载新的HTML文档&…

7综合项目 旅游网 【7.精选分类】

精选旅游人气旅游→收藏次数最高最新旅游→日期最新主题旅游→主题关键字相同在首页将精选的内容动态展示的实现分析首页中的精选包含“人气旅游”、“最新旅游”、“主题旅游”三个部分index.html//页面加载完成,发送ajax请求根据点击不同分类展示不同内容人气旅游→收藏次数最…

分享17个提升开发效率的工具“轮子”

本文是向大家介绍平时在开发中经常用到的小工具&#xff0c;它能够极大得提升我们的开发效率&#xff0c;能够解决平时开发中遇到的问题。前言在java的庞大体系中&#xff0c;其实有很多不错的小工具&#xff0c;也就是我们平常说的“轮子“。如果在我们的日常工作当中&#xf…

数据结构课程设计:高铁信息管理系统(C++实现)

目录 简介实验输出实验要求代码运行环境结语简介 Hello! 非常感谢您阅读海轰的文章,倘若文中有错误的地方,欢迎您指出~ ଘ(੭ˊᵕˋ)੭ 昵称:海轰 标签:程序猿|C++选手|学生 简介:因C语言结识编程,随后转入计算机专业,获得过国家奖学金,有幸在竞赛中拿过一些国奖…

嵌入式Linux驱动开发(一)chrdevbase虚拟字符设备

Linux下三大驱动&#xff1a;字符设备&#xff0c;块设备&#xff0c;网络设备。一个硬件可以从属于不同的设备分类。 0. Linux应用程序对驱动程序的调用流程 驱动加载成功后会在/dev目录下生成一个文件&#xff0c;对该文件的操作就是对设备的操作。当我们在用户态调用一个函…

Element-UI实现复杂table表格结构

Element-UI组件el-table用于展示多条结构类似的数据&#xff0c;可对数据进行排序、筛选、对比或其他自定义操作。将使用到以下两项&#xff0c;来完成今天demo演示&#xff1a;多级表头&#xff1a;数据结构比较复杂的时候&#xff0c;可使用多级表头来展现数据的层次关系。合…

Web3中文|Web3CN加速器第二期「Web3项目征集」火热报名

Web3CN加速器第二期「Web3项目征集」火热征集中&#xff0c;本次征集活动是由Web3CN加速器联合专业web3媒体Web3CN、VC机构Tiger VC DAO核心发起&#xff0c;数百家加密VC机构、加密社区等联合发起的&#xff0c;为早期Web3创新创业项目提供加速服务。如果你正在进行web3相关的…

VC常见问题(.obj : error LNK2019、fatal error C1083、编译64位Detours)

VC常用问题VC常见问题*.obj : error LNK2019: 无法解析的外部符号 __imp_FindWindow ,该符号在函数 YAWindows环境下用nmake编译常见问题fatal error C1083: 无法打开包括文件:“excpt.h”vs2012编译64位Detours&#xff08;其他vs版本同理&#xff09;vs项目设置选项编译使用了…

Java基础面试题(三)

Java基础面试题 一、JavaWeb专题 1.HTTP响应码有哪些 1、1xx&#xff08;临时响应&#xff09; 2、2xx&#xff08;成功&#xff09; 3、3xx&#xff08;重定向&#xff09;&#xff1a;表示要完成请求需要进一步操作 4、4xx&#xff08;错误&#xff09;&#xff1a;表示请…

Nuxt实战教程基础-Day01

Nuxt实战教程基础-Day01Nuxt是什么&#xff1f;Nuxt.js框架是如何运作的&#xff1f;Nuxt特性流程图服务端渲染(通过 SSR)单页应用程序 (SPA)静态化 (预渲染)Nuxt优缺点优点缺点安装运行项目总结前言&#xff1a;本教程基于Nuxt2&#xff0c;作为教程的第一天&#xff0c;我们先…

BUUCTF-[RoarCTF2019]polyre

题目下载&#xff1a;下载 这道题目是一个关于控制流平坦化和虚假流程。 首先了解一下控制流平坦化&#xff1a;利用符号执行去除控制流平坦化 - 博客 - 腾讯安全应急响应中心https://www.cnblogs.com/zhwer/p/14081454.htmlbuuctf RoarCTF2019 polyre writeup - 『脱壳破解区…

单点登录的几种实现方式探讨

单点登录&#xff08;Single Sign On&#xff09;&#xff0c;简称为 SSO&#xff0c;是解决企业内部的一系列产品登录问题的方案。SSO 的定义是在多个应用系统中&#xff0c;用户只需要登录一次就可以访问所有相互信任的应用系统&#xff0c;用于减少用户重复的登录操作&#…

PyTorch的自动微分(autograd)

PyTorch的自动微分(autograd) 计算图 计算图是用来描述运算的有向无环图 计算图有两个主要元素&#xff1a;结点&#xff08;Node&#xff09;和边&#xff08;Edge&#xff09; 结点表示数据&#xff0c;如向量、矩阵、张量 边表示运算&#xff0c;如加减乘除卷积等 用计算…

共话开源 | 开放原子开源基金会专题调研openKylin社区!

3月8日&#xff0c;开放原子开源基金会秘书长冯冠霖、运营部部长李博、业务发展部部长朱其罡、研发部副部长周济一行莅临openKylin社区调研交流&#xff0c;麒麟软件高级副总经理韩乃平、副总裁董军平、终端研发部副总经理陆展、产品规划部经理常亚武、市场与政府事务部高级经理…

力扣sql简单篇练习(二十五)

力扣sql简单篇练习(二十五) 1 无效的推文 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # Write your MySQL query statement below SELECT tweet_id FROM Tweets WHERE CHAR_LENGTH(content)>151.3 运行截图 2 求关注者的数量 2.1 基本题目内…