写点什么

Android 源码分析笔记:(2021-3-13)事件分发

用户头像
Geek_416be1
关注
发布于: 2021 年 03 月 13 日

事件分发机制:


首先,上代码和界面。


package net.jxvtc.advance001_event;
复制代码


复制代码


import androidx.appcompat.app.AppCompatActivity;
复制代码


复制代码


import android.annotation.SuppressLint;
复制代码


import android.os.Bundle;
复制代码


import android.util.Log;
复制代码


import android.view.MotionEvent;
复制代码


import android.view.View;
复制代码


import android.widget.Button;
复制代码


复制代码


public class MainActivity extends AppCompatActivity {
复制代码


    Button btn_press;
复制代码


    @Override
复制代码


    protected void onCreate(Bundle savedInstanceState) {
复制代码


        super.onCreate(savedInstanceState);
复制代码


        setContentView(R.layout.activity_main);
复制代码


        btn_press=findViewById(R.id.btn_press);
复制代码


        btn_press.setOnClickListener(new View.OnClickListener() {
复制代码


            @Override
复制代码


            public void onClick(View v) {
复制代码


                Log.d("TAG", "onClick: ");
复制代码


            }
复制代码


        });
复制代码


        btn_press.setOnTouchListener(new View.OnTouchListener() {
复制代码


            @SuppressLint("ClickableViewAccessibility")
复制代码


            @Override
复制代码


            public boolean onTouch(View v, MotionEvent event) {
复制代码


                Log.d("TAG", "onTouch: "+event.getAction());
复制代码


                return false;
复制代码


            }
复制代码


        });
复制代码


复制代码


    }
复制代码


}
复制代码


复制代码


<?xml version="1.0" encoding="utf-8"?>
复制代码


<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
复制代码


    xmlns:app="http://schemas.android.com/apk/res-auto"
复制代码


    xmlns:tools="http://schemas.android.com/tools"
复制代码


    android:layout_width="match_parent"
复制代码


    android:layout_height="match_parent"
复制代码


    tools:context=".MainActivity">
复制代码


复制代码


    <Button
复制代码


        android:id="@+id/btn_press"
复制代码


        android:layout_width="wrap_content"
复制代码


        android:layout_height="wrap_content"
复制代码


        android:text="点击我"
复制代码


        app:layout_constraintBottom_toBottomOf="parent"
复制代码


        app:layout_constraintLeft_toLeftOf="parent"
复制代码


        app:layout_constraintRight_toRightOf="parent"
复制代码


        app:layout_constraintTop_toTopOf="parent" />
复制代码


复制代码


</androidx.constraintlayout.widget.ConstraintLayout>
复制代码


运行点击按钮后,日志输出为:


2021-03-13 20:13:33.490 7177-7177/net.jxvtc.advance001_event D/TAG: onTouch: 02021-03-13 20:13:33.612 7177-7177/net.jxvtc.advance001_event D/TAG: onTouch: 12021-03-13 20:13:33.649 7177-7177/net.jxvtc.advance001_event D/TAG: onClick:


如果修改上述的 Java 代码把 onTouch 方法中的


return false;改成 return true;


日志输出将变为:


2021-03-13 20:13:44.647 7357-7357/net.jxvtc.advance001_event D/TAG: onTouch: 02021-03-13 20:13:44.744 7357-7357/net.jxvtc.advance001_event D/TAG: onTouch: 1


为什么呢?


通过源码来找寻答案:


1、当点击 Button 时,首先会执行 View 的 dispatchTouchEvent 方法:


View.java


 /**
复制代码


     * Pass the touch screen motion event down to the target view, or this
复制代码


     * view if it is the target.
复制代码


     *
复制代码


     * @param event The motion event to be dispatched.
复制代码


     * @return True if the event was handled by the view, false otherwise.
复制代码


     */
复制代码


    public boolean dispatchTouchEvent(MotionEvent event) {
复制代码


     //核心代码如下:
复制代码


 if (onFilterTouchEventForSecurity(event)) {
复制代码


            //这句肯定进入
复制代码


            if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
复制代码


                result = true;
复制代码


            }
复制代码


            //noinspection SimplifiableIfStatement
复制代码


            ListenerInfo li = mListenerInfo; //这个具体见下面的代码,也不为空
复制代码


            if (li != null && li.mOnTouchListener != null
复制代码


                    && (mViewFlags & ENABLED_MASK) == ENABLED
复制代码


                    && li.mOnTouchListener.onTouch(this, event)) {
复制代码


                //如果onTouch返回true的话 result:true
复制代码


                result = true;
复制代码


            }
复制代码


            //如果result是false,则取决于onTouchEvent的取值,
复制代码


            //如果上面onTouch返回的是false,并且onTouchEvent为true,则结果为true.
复制代码


            if (!result && onTouchEvent(event)) {
复制代码


                result = true;
复制代码


            }
复制代码


        }
复制代码


        
复制代码


    }
复制代码


MainActivity.java


 btn_press.setOnTouchListener(new View.OnTouchListener() {
复制代码


View.java


  /**
复制代码


     * Register a callback to be invoked when a touch event is sent to this view.
复制代码


     * @param l the touch listener to attach to this view
复制代码


     */
复制代码


    public void setOnTouchListener(OnTouchListener l) {
复制代码


        getListenerInfo().mOnTouchListener = l;
复制代码


    }
复制代码


复制代码


     @UnsupportedAppUsage
复制代码


    ListenerInfo getListenerInfo() {
复制代码


        if (mListenerInfo != null) {
复制代码


            return mListenerInfo;
复制代码


        }
复制代码


        mListenerInfo = new ListenerInfo();
复制代码


        return mListenerInfo;
复制代码


    }
复制代码


复制代码


 /**
复制代码


     * Implement this method to handle touch screen motion events.
复制代码


     * <p>
复制代码


     * If this method is used to detect click actions, it is recommended that
复制代码


     * the actions be performed by implementing and calling
复制代码


     * {@link #performClick()}. This will ensure consistent system behavior,
复制代码


     * including:
复制代码


     * <ul>
复制代码


     * <li>obeying click sound preferences
复制代码


     * <li>dispatching OnClickListener calls
复制代码


     * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when
复制代码


     * accessibility features are enabled
复制代码


     * </ul>
复制代码


     *
复制代码


     * @param event The motion event.
复制代码


     * @return True if the event was handled, false otherwise.
复制代码


     */
复制代码


    public boolean onTouchEvent(MotionEvent event) {
复制代码


    if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
复制代码


            switch (action) {
复制代码


                case MotionEvent.ACTION_UP:
复制代码


                  
复制代码


                                if (mPerformClick == null) {
复制代码


                                    mPerformClick = new PerformClick();
复制代码


                                }
复制代码


                                if (!post(mPerformClick)) {
复制代码


                                    performClickInternal();
复制代码


                                }
复制代码


                            }
复制代码


                        }
复制代码


复制代码


                      
复制代码


复制代码


                     
复制代码


                    }
复制代码


                    mIgnoreNextUpEvent = false;
复制代码


                    break;
复制代码


        
复制代码


        
复制代码


    }
复制代码


复制代码


/**
复制代码


     * Entry point for {@link #performClick()} - other methods on View should call it instead of
复制代码


     * {@code performClick()} directly to make sure the autofill manager is notified when
复制代码


     * necessary (as subclasses could extend {@code performClick()} without calling the parent's
复制代码


     * method).
复制代码


     */
复制代码


    private boolean performClickInternal() {
复制代码


        // Must notify autofill manager before performing the click actions to avoid scenarios where
复制代码


        // the app has a click listener that changes the state of views the autofill service might
复制代码


        // be interested on.
复制代码


        notifyAutofillManagerOnClick();
复制代码


复制代码


        return performClick();
复制代码


    }
复制代码


复制代码


  public boolean performClick() {
复制代码


        // We still need to call this method to handle the cases where performClick() was called
复制代码


        // externally, instead of through performClickInternal()
复制代码


        notifyAutofillManagerOnClick();
复制代码


复制代码


        final boolean result;
复制代码


        final ListenerInfo li = mListenerInfo;
复制代码


        if (li != null && li.mOnClickListener != null) {
复制代码


            playSoundEffect(SoundEffectConstants.CLICK);
复制代码


            li.mOnClickListener.onClick(this);//点击事件
复制代码


            result = true;
复制代码


        } else {
复制代码


            result = false;
复制代码


        }
复制代码


复制代码


        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
复制代码


复制代码


        notifyEnterOrExitForAutoFillIfNeeded(true);
复制代码


复制代码


        return result;
复制代码


    }
复制代码


用户头像

Geek_416be1

关注

还未添加个人签名 2020.08.27 加入

还未添加个人简介

评论

发布
暂无评论
Android源码分析笔记:(2021-3-13)事件分发