Android开发学习教程(7)- 详解Android Button点击事件原理

209 阅读3分钟

—— 只有你成功了,才有选择的权力,才会被更多的人尊重。

上一篇我们知道了Button的基本用法,最后讲到了Button的点击事件是通过setOnClickListener方法来实现的。那么APP是如果把用户的点击动作和setOnClickListener关联起来的呢,要弄明白这个问题,我们先来看看APP中是什么时侯处理用户点击动作的。要看问题还得从代码看起,这里以上一篇中的Button基本用法项目举例,打开TestActivity点击事件的主要代码:

123456button.setOnClickListener(``new View.OnClickListener() {``    ``@Override``    ``public void onClick(View v) {``        ``Toast.makeText(TestActivity.``this``, ``"我被点击了"``, Toast.LENGTH_SHORT).show();``    ``}``});

我们来看setOnClickListener的源码:

12345678910111213141516171819202122232425/**`` ``* Register a callback to be invoked when this view is clicked. If this view is not`` ``* clickable, it becomes clickable.`` ``*`` ``* @param l The callback that will run`` ``*`` ``* @see #setClickable(boolean)`` ``*/``public void setOnClickListener(``@Nullable OnClickListener l) {``    ``if (!isClickable()) {``        ``setClickable(``true``);``    ``}``    ``getListenerInfo().mOnClickListener = l;``}``注释写的很明白,注册一个当view被点击时的回调方法。可以看到把回调方案OnClickListener传给了getListenerInfo().mOnClickListener,getListenerInfo()跟进去:``static class ListenerInfo {``    ``@UnsupportedAppUsage``    ``ListenerInfo() {``    ``}``...``...``}

一个静态类而已,里面定义了一堆接口,包括上面传递的点击事件mOnClickListener ,那么mOnClickListener 什么时侯被调用,view里面有一个onTouchEvent方法:

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556/**``*实现此方法以处理触摸屏幕移动事件。``*包括:``*1. 播放单击声音``*2. 调用OnClickListener``*/``public boolean onTouchEvent(MotionEvent event) {``    ``...``...``// 如果是可点击的``    ``if (clickable) {``        ``switch (action) {``// ACTION_UP 手指触摸屏幕抬起事件``            ``case MotionEvent.ACTION_UP:``                ``...``// 如果不可点击的,那么移出所有相关回调,并跳出循环``                ``if (!clickable) {``                    ``removeTapCallback();``                    ``removeLongPressCallback();``                    ``mInContextButtonPress = ``false``;``                    ``mHasPerformedLongPress = ``false``;``                    ``mIgnoreNextUpEvent = ``false``;``                    ``break``;``                ``}``// 如果view是被按下的状态(说明在手指按下时按的是这个view)``                ``if (prepressed) {``                    ``boolean focusTaken = ``false``;``                    ``if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {``                        ``focusTaken = requestFocus();``                    ``}``                       ``// 设置按下状态``                    ``if (prepressed) {``                        ``setPressed(``true``, x, y);``                    ``}``                    ``if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {``// 能到这一步说明是单击事件,那么移除长按事件的回调``                        ``removeLongPressCallback();``                        ``if (!focusTaken) {``                            ``// 创建一个执行点击回调的子线程``                            ``if (mPerformClick == ``null``) {``                                ``mPerformClick = ``new PerformClick();``                            ``}``// 把子线程添加到UI线程的消息对列中等待处理``                            ``if (!post(mPerformClick)) {``                                ``performClickInternal();``                            ``}``                        ``}``                    ``}``                    ``...``                    ``removeTapCallback();``                ``}

上面那个执行点击回调的子线程:

1234567891011121314151617181920public boolean performClick() {``    ``...``    ``final boolean result;``// 这里的mListenerInfo就是我们在Activity中setOnClickListener传递过来的``    ``final ListenerInfo li = mListenerInfo;``    ``if (li != ``null && li.mOnClickListener != ``null``) {``        ``playSoundEffect(SoundEffectConstants.CLICK);``// 具体在这执行回调,即Activity中的public void onClick(View v) {...}``        ``li.mOnClickListener.onClick(``this``);``        ``result = ``true``;``    ``} ``else {``        ``result = ``false``;``    ``}``    ``...``    ``return result;``}