IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android事件分发机制(2)-setOnCLickLinstener 执行流程 -> 正文阅读

[移动开发]Android事件分发机制(2)-setOnCLickLinstener 执行流程

阅读之前建议先看从源码分析Android 事件分发机制_z936689039的博客-CSDN博客,可以更方便的理解里面奥妙

setOnCLickLinstener,只要写过 Android 的同学应该都见过,大家都知道是点击事件监听,但是是怎么实现的呢?对,你没有猜错,就是回调
你在 onClick(View view)中写的方法,就是一个回调方法,然后通过这个方法实现了点击监听,那么问题来了,这个方法它没有在activity或者fragment里头出现,那它是怎么实现的呢,下面直接从源码的角度看这玩意咋跑的

 tvKes.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

先整个点击事件监听,然后ctrl点那个setOnClickListener方法进去看,然后我们会看到

   public void setOnClickListener(@Nullable OnClickListener l) {
        if (!isClickable()) {
            setClickable(true);
        }
        getListenerInfo().mOnClickListener = l;
    }
这段代码意思就是说将点击状态设置为true,其中setOnClickListener 方法就如同我们调用时的那样,传入一个 OnClickListener 对象作为参数,那我们来看一看 OnClickListener 是个啥子
 public interface OnClickListener {
        /**
         * Called when a view has been clicked.
         *
         * @param v The view that was clicked.
         */
        void onClick(View v);
    }
果然如我们所料,这个是个接口来的。
同时我们注意到getListenerInfo()这个方法,哎,就是玩,点进去看是什么鬼

//getListenerInfo()返回一个 ListenerInfo,如果 mListenerInfo 已经存在,
//就返回,如果不存在,就 new 一个返回
    @UnsupportedAppUsage
    ListenerInfo getListenerInfo() {
        if (mListenerInfo != null) {
            return mListenerInfo;
        }
        mListenerInfo = new ListenerInfo();
        return mListenerInfo;
    }


  static class ListenerInfo {

        @UnsupportedAppUsage
        ListenerInfo() {
        }

        /**
         * Listener used to dispatch focus change events.
         * This field should be made private, so it is hidden from the SDK.
         * {@hide}
         */
        @UnsupportedAppUsage
        protected OnFocusChangeListener mOnFocusChangeListener;

        /**
         * Listeners for layout change events.
         */
        private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners;

        protected OnScrollChangeListener mOnScrollChangeListener;

        /**
         * Listeners for attach events.
         */
        private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners;

        /**
         * Listener used to dispatch click events.
         * This field should be made private, so it is hidden from the SDK.
         * {@hide}
         */
        @UnsupportedAppUsage
        public OnClickListener mOnClickListener;

        /**
         * Listener used to dispatch long click events.
         * This field should be made private, so it is hidden from the SDK.
         * {@hide}
         */
        @UnsupportedAppUsage
        protected OnLongClickListener mOnLongClickListener;

        /**
         * Listener used to dispatch context click events. This field should be made private, so it
         * is hidden from the SDK.
         * {@hide}
         */
        protected OnContextClickListener mOnContextClickListener;

        /**
         * Listener used to build the context menu.
         * This field should be made private, so it is hidden from the SDK.
         * {@hide}
         */
        @UnsupportedAppUsage
        protected OnCreateContextMenuListener mOnCreateContextMenuListener;

        @UnsupportedAppUsage
        private OnKeyListener mOnKeyListener;

        @UnsupportedAppUsage
        private OnTouchListener mOnTouchListener;

        @UnsupportedAppUsage
        private OnHoverListener mOnHoverListener;

        @UnsupportedAppUsage
        private OnGenericMotionListener mOnGenericMotionListener;

        @UnsupportedAppUsage
        private OnDragListener mOnDragListener;

        private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;

        OnApplyWindowInsetsListener mOnApplyWindowInsetsListener;

        OnCapturedPointerListener mOnCapturedPointerListener;

        private ArrayList<OnUnhandledKeyEventListener> mUnhandledKeyListeners;

        WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback;

        /**
         * This lives here since it's only valid for interactive views.
         */
        private List<Rect> mSystemGestureExclusionRects;

        /**
         * Used to track {@link #mSystemGestureExclusionRects}
         */
        public RenderNode.PositionUpdateListener mPositionUpdateListener;

        /**
         * Allows the application to implement custom scroll capture support.
         */
        ScrollCaptureCallback mScrollCaptureCallback;
    }

?从中我们发现getListenerInfo()是获取一个ListenerInfo的内部静态类,其中我们发现OnClickListener跟OnLongClickListener均是其接口引用.再回到view中的setOnClickListener,我们发现它本质上就是将我们传递进去的OnClickListener实现类赋值给了ListenerInfo的mOnClickListener 对象,然后ctrl这个对象,看它在哪里调用了其onClick方法

然后我们发现在view的performClick中有调用到

然后再看performClick在哪里调用的

?最终指向的是View的onTouchEvent的ACTION_UP的时候调用的,其中实现是用PerformClick异步执行,若不成功再调用performClick(),performClick()则执行OnClickListener中的onClick方法

然后用断点的方式去分析实际执行过程

我们看到它先执行了DetorView的dispatchEvent

然后执行了activity的dispatchTouchEvent


然后执行了View的dispatchTouchEvent


然后再这个方法里头执行onTouchEvent方法


因为onClick事件在手势上分成3个动作按下(MotionEvent.ACTION_DOWN),抬起(MotionEvent.ACTION_UP),所以它会先执行MotionEvent.ACTION_DOWN,此时VIew的dispatchTouchEvent返回true的,于是又回到了DetorView的dispatchTouchEvent中

可以发现在ACTION_UP方法的时候执行了点击操作,然后同样还是这一系列操作执行完后View的dispatchTouchEvent还是返回true,然后又回到了梦开始的地方,detorView的dispatchTouchEvent

然后同时执行了点击的方法操作

然后就很明了啦,后面就执行了onClick的执行方法了

到这里整个流程就走完了
其中布局是这样的:


总结:
?onClickListener点击事件流程就是:DetorView:dispatchTouchEvent->Activity:dispatchTouchEvent->View:disPatchTouchEvent->View:onTouchEvent->View:OnTouchEvent-ACTION_DOWN->.然后把前面的流程走遍->View:OnTouchEvent-ACTION_UP->performClick->DetorView:dispatchTouchEvent

问题:

1.onTouchEvent,OnClickListener,dispatchTouchEvent,onTouch四者执行的顺序?

答:dispatchTouchEvent->onTouch->onTouchEvent->OnClickListener,因为在onTouche在disPatchTouchEvent会提前判断的,这块在之前文章也提到过,如果onTouchLisener.onTouch返回true的话,那么View的onTouchEvent就不会走了,所以如果你写了2个方法,一个是setOnClickListener和一个setOnTouchEvent,并且setOnTouchEvent返回true的话,那么根据刚刚的流程,此时是会直接执行View的onTouch方法的,而不会执行setOnClick.onClick方法的

 
 

 
 

                
        
        
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-11-29 16:26:00  更:2021-11-29 16:27:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 5:35:27-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码