android事件分发log打印,Android事件传递和分发机制

PS:之前写的有些地方不够清楚,配图也有点小问题,特此更正了下。2017-9-18

今天看了Android事件分发的一些资料,自己也研究了源码,了解了事件分发的流程和机制,特此记录下。

首先自定义了两个View,一个Button,一个LinearLayout,分别重写了onTouchEvent、dispatchTouchEvent、onFilterTouchEventForSecurity这三个方法。代码如下:

public class MyButton extends AppCompatButton {

private static final String TAG = "TestTouchEventButton";

public MyButton(Context context) {

super(context);

}

public MyButton(Context context, AttributeSet attrs) {

super(context, attrs);

}

@Override

public boolean onTouchEvent(MotionEvent event) {

Log.i(TAG, "onTouchEvent: "+event.getAction());

// super.onTouchEvent(event);

return super.onTouchEvent(event);

}

@Override

public boolean dispatchTouchEvent(MotionEvent event) {

Log.i(TAG, "dispatchTouchEvent: "+event.getAction());

return super.dispatchTouchEvent(event);

}

@Override

public boolean onFilterTouchEventForSecurity(MotionEvent event) {

Log.i(TAG, "onFilterTouchEventForSecurity: "+event.getAction());

return super.onFilterTouchEventForSecurity(event);

}

}

public class MyLayout extends LinearLayout {

private static final String TAG = "TestTouchEventLayout";

public MyLayout(Context context) {

super(context);

}

public MyLayout(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

}

@Override

public boolean onTouchEvent(MotionEvent event) {

Log.i(TAG, "onTouchEvent: "+event.getAction());

return super.onTouchEvent(event);

}

@Override

public boolean dispatchTouchEvent(MotionEvent ev) {

Log.i(TAG, "dispatchTouchEvent: "+ev.getAction());

return super.dispatchTouchEvent(ev);

}

@Override

public boolean onFilterTouchEventForSecurity(MotionEvent event) {

Log.i(TAG, "onFilterTouchEventForSecurity: ");

return super.onFilterTouchEventForSecurity(event);

}

}

//activity

public class TestTouchDispatchActivity extends BaseActivity {

private static final String TAG = "TestTouchEventActivity";

@BindView(R.id.btn)

MyButton mBtn;

@Override

protected void initPresenter() {

}

@Override

protected int attachLayoutRes() {

return R.layout.activity_test_touch_dispatch;

}

@Override

protected void initViews() {

mBtn.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

Log.i(TAG, "onClick: ");

}

});

mBtn.setOnTouchListener(new View.OnTouchListener() {

@Override

public boolean onTouch(View v, MotionEvent event) {

Log.i(TAG, "onTouch: "+event.getAction());

return false;

}

});

}

}

//布局文件

xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent">

android:id="@+id/btn"

android:text="CLICK"

android:layout_width="match_parent"

android:layout_height="wrap_content"/>

一、先屏蔽掉MyLayout中的log,只看Button里面的事件分发和传递情况(PS:每项对比后直接说正确的结论,后面在从源码层面分析):

1.onTouch方法里面返回true和false,打印log如下:

mBtn.setOnTouchListener(new View.OnTouchListener() {

@Override

public boolean onTouch(View v, MotionEvent event) {

Log.i(TAG, "onTouch: "+event.getAction());

return true/false;

}

});

//true

07-27 18:45:56.160 16726-16726/com.sleep.sunshine I/TestTouchEventButton: dispatchTouchEvent: 0

07-27 18:45:56.160 16726-16726/com.sleep.sunshine I/TestTouchEventButton: onFilterTouchEventForSecurity: 0

07-27 18:45:56.160 16726-16726/com.sleep.sunshine I/TestTouchEventActivity: onTouch: 0

07-27 18:45:56.277 16726-16726/com.sleep.sunshine I/TestTouchEventButton: dispatchTouchEvent: 1

07-27 18:45:56.277 16726-16726/com.sleep.sunshine I/TestTouchEventButton: onFilterTouchEventForSecurity: 1

07-27 18:45:56.277 16726-16726/com.sleep.sunshine I/TestTouchEventActivity: onTouch: 1

//false

07-27 18:43:04.297 14262-14262/com.sleep.sunshine I/TestTouchEventButton: dispatchTouchEvent: 0

07-27 18:43:04.297 14262-14262/com.sleep.sunshine I/TestTouchEventButton: onFilterTouchEventForSecurity: 0

07-27 18:43:04.297 14262-14262/com.sleep.sunshine I/TestTouchEventActivity: onTouch: 0

07-27 18:43:04.297 14262-14262/com.sleep.sunshine I/TestTouchEventButton: onTouchEvent: 0

07-27 18:43:04.373 14262-14262/com.sleep.sunshine I/TestTouchEventButton: dispatchTouchEvent: 1

07-27 18:43:04.373 14262-14262/com.sleep.sunshine I/TestTouchEventButton: onFilterTouchEventForSecurity: 1

07-27 18:43:04.374 14262-14262/com.sleep.sunshine I/TestTouchEventActivity: onTouch: 1

07-27 18:43:04.374 14262-14262/com.sleep.sunshine I/TestTouchEventButton: onTouchEvent: 1

07-27 18:43:04.374 14262-14262/com.sleep.sunshine I/TestTouchEventActivity: onClick:

# 对比结论:onTouch返回true后,不会再调用onTouchEvent和onClick方法。

2.将MyButton里面的onTouchEvent方法里面返回分别返回true和false,打印log如下:

@Override

public boolean onTouchEvent(MotionEvent event) {

Log.i(TAG, "onTouchEvent: "+event.getAction());

return true/false;

}

//true

07-27 18:51:28.626 19877-19877/com.sleep.sunshine I/TestTouchEventButton: dispatchTouchEvent: 0

07-27 18:51:28.626 19877-19877/com.sleep.sunshine I/TestTouchEventButton: onFilterTouchEventForSecurity: 0

07-27 18:51:28.626 19877-19877/com.sleep.sunshine I/TestTouchEventActivity: onTouch: 0

07-27 18:51:28.626 19877-19877/com.sleep.sunshine I/TestTouchEventButton: onTouchEvent: 0

07-27 18:51:28.665 19877-19877/com.sleep.sunshine I/TestTouchEventButton: dispatchTouchEvent: 1

07-27 18:51:28.665 19877-19877/com.sleep.sunshine I/TestTouchEventButton: onFilterTouchEventForSecurity: 1

07-27 18:51:28.665 19877-19877/com.sleep.sunshine I/TestTouchEventActivity: onTouch: 1

07-27 18:51:28.665 19877-19877/com.sleep.sunshine I/TestTouchEventButton: onTouchEvent: 1

//false

07-27 18:52:23.649 20415-20415/com.sleep.sunshine I/TestTouchEventButton: dispatchTouchEvent: 0

07-27 18:52:23.649 20415-20415/com.sleep.sunshine I/TestTouchEventButton: onFilterTouchEventForSecurity: 0

07-27 18:52:23.649 20415-20415/com.sleep.sunshine I/TestTouchEventActivity: onTouch: 0

07-27 18:52:23.649 20415-20415/com.sleep.sunshine I/TestTouchEventButton: onTouchEvent: 0

# 对比结论:a、onTouchEvent返回false,代表不再接受同组的事件(ACTION_DOWN= 0 ,ACTION_UP=1)

#b、和上面的1对比说明onClick方法是在super.onTouchEvent(event)方法里面调用的。事实证明查看源码也能发现这一点:

//父类TextView的onTouchEvent方法。

@Override

public boolean onTouchEvent(MotionEvent event) {

......

final boolean textIsSelectable = isTextSelectable();

if (touchIsFinished && mLinksClickable && mAutoLinkMask != 0 && textIsSelectable) {

// The LinkMovementMethod which should handle taps on links has not been installed

// on non editable text that support text selection.

// We reproduce its behavior here to open links for these.

ClickableSpan[] links = ((Spannable) mText).getSpans(getSelectionStart(),

getSelectionEnd(), ClickableSpan.class);

if (links.length > 0) {

links[0].onClick(this);

handled = true;

}

}

......

return superResult;

}

3.将MyButton里面的onFilterTouchEventForSecurity方法里面返回分别返回true和false,打印log如下:

@Override

public boolean onFilterTouchEventForSecurity(MotionEvent event) {

Log.i(TAG, "onFilterTouchEventForSecurity: "+event.getAction());

return true/false;

}

//true

07-27 19:13:40.029 32428-32428/com.sleep.sunshine I/TestTouchEventButton: dispatchTouchEvent: 0

07-27 19:13:40.029 32428-32428/com.sleep.sunshine I/TestTouchEventButton: onFilterTouchEventForSecurity: 0

07-27 19:13:40.029 32428-32428/com.sleep.sunshine I/TestTouchEventActivity: onTouch: 0

07-27 19:13:40.029 32428-32428/com.sleep.sunshine I/TestTouchEventButton: onTouchEvent: 0

07-27 19:13:40.082 32428-32428/com.sleep.sunshine I/TestTouchEventButton: dispatchTouchEvent: 1

07-27 19:13:40.082 32428-32428/com.sleep.sunshine I/TestTouchEventButton: onFilterTouchEventForSecurity: 1

07-27 19:13:40.082 32428-32428/com.sleep.sunshine I/TestTouchEventActivity: onTouch: 1

07-27 19:13:40.082 32428-32428/com.sleep.sunshine I/TestTouchEventButton: onTouchEvent: 1

07-27 19:13:40.083 32428-32428/com.sleep.sunshine I/TestTouchEventActivity: onClick:

//false

07-27 19:15:31.465 1655-1655/com.sleep.sunshine I/TestTouchEventButton: dispatchTouchEvent: 0

07-27 19:15:31.467 1655-1655/com.sleep.sunshine I/TestTouchEventButton: onFilterTouchEventForSecurity: 0

4.将MyButton里面的dispatchTouchEvent方法里面返回分别返回true和false,打印log如下:

@Override

public boolean dispatchTouchEvent(MotionEvent event) {

Log.i(TAG, "dispatchTouchEvent: "+event.getAction());

return true/false;

}

//true

07-27 19:19:09.215 4026-4026/com.sleep.sunshine I/TestTouchEventButton: dispatchTouchEvent: 0

07-27 19:19:09.264 4026-4026/com.sleep.sunshine I/TestTouchEventButton: dispatchTouchEvent: 1

//false

07-27 19:19:46.849 4676-4676/com.sleep.sunshine I/TestTouchEventButton: dispatchTouchEvent: 0

#结论:View 中的dispatchTouchEvent通过开关onFilterTouchEventForSecurity(低版本的API是用的onInterceptTouchEvent)里面控制着onTouch和onTouchEvent的调用,而且可以看到当onTouch返回true的时候,就不会调用onTouchEvent方法了,证明了1中的现象。

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

result = true;

}

if (!result && onTouchEvent(event)) {

result = true;

}

}

.....

return result;

}

button事件分发小节:

31e20def82c2

2428413-fc026fbb6243cad7.png

二、在有父布局Layout的情况下的事件分发直接说结论了,有兴趣的同学可以参考上面的方法去打印Log或者翻看源码。

1、不做任何改变时的log

09-18 10:09:45.327 31952-31952/com.sleep.sunshine I/TestTouchEventLayout: dispatchTouchEvent: 0

09-18 10:09:45.327 31952-31952/com.sleep.sunshine I/TestTouchEventLayout: onFilterTouchEventForSecurity:

09-18 10:09:45.327 31952-31952/com.sleep.sunshine I/TestTouchEventButton: dispatchTouchEvent: 0

09-18 10:09:45.327 31952-31952/com.sleep.sunshine I/TestTouchEventButton: onFilterTouchEventForSecurity: 0

09-18 10:09:45.327 31952-31952/com.sleep.sunshine I/TestTouchEventActivity: onTouch: 0

09-18 10:09:45.327 31952-31952/com.sleep.sunshine I/TestTouchEventButton: onTouchEvent: 0

09-18 10:09:45.392 31952-31952/com.sleep.sunshine I/TestTouchEventLayout: dispatchTouchEvent: 2

09-18 10:09:45.392 31952-31952/com.sleep.sunshine I/TestTouchEventLayout: onFilterTouchEventForSecurity:

09-18 10:09:45.392 31952-31952/com.sleep.sunshine I/TestTouchEventButton: dispatchTouchEvent: 2

09-18 10:09:45.392 31952-31952/com.sleep.sunshine I/TestTouchEventButton: onFilterTouchEventForSecurity: 2

09-18 10:09:45.392 31952-31952/com.sleep.sunshine I/TestTouchEventActivity: onTouch: 2

09-18 10:09:45.392 31952-31952/com.sleep.sunshine I/TestTouchEventButton: onTouchEvent: 2

09-18 10:09:45.396 31952-31952/com.sleep.sunshine I/TestTouchEventLayout: dispatchTouchEvent: 1

09-18 10:09:45.396 31952-31952/com.sleep.sunshine I/TestTouchEventLayout: onFilterTouchEventForSecurity:

09-18 10:09:45.396 31952-31952/com.sleep.sunshine I/TestTouchEventButton: dispatchTouchEvent: 1

09-18 10:09:45.396 31952-31952/com.sleep.sunshine I/TestTouchEventButton: onFilterTouchEventForSecurity: 1

09-18 10:09:45.396 31952-31952/com.sleep.sunshine I/TestTouchEventActivity: onTouch: 1

09-18 10:09:45.396 31952-31952/com.sleep.sunshine I/TestTouchEventButton: onTouchEvent: 1

09-18 10:09:45.397 31952-31952/com.sleep.sunshine I/TestTouchEventActivity: onClick:

2、将MyButton的onFilterTouchEventForSecurity 方法里直接返回false

@Override

public boolean onFilterTouchEventForSecurity(MotionEvent event) {

Log.i(TAG, "onFilterTouchEventForSecurity: "+event.getAction());

// return super.onFilterTouchEventForSecurity(event);

return false;

}

09-18 10:13:33.888 1386-1386/com.sleep.sunshine I/TestTouchEventLayout: dispatchTouchEvent: 0

09-18 10:13:33.888 1386-1386/com.sleep.sunshine I/TestTouchEventLayout: onFilterTouchEventForSecurity:

09-18 10:13:33.888 1386-1386/com.sleep.sunshine I/TestTouchEventButton: dispatchTouchEvent: 0

09-18 10:13:33.888 1386-1386/com.sleep.sunshine I/TestTouchEventButton: onFilterTouchEventForSecurity: 0

09-18 10:13:33.888 1386-1386/com.sleep.sunshine I/TestTouchEventLayout: onFilterTouchEventForSecurity:

09-18 10:13:33.889 1386-1386/com.sleep.sunshine I/TestTouchEventActivity: onTouch layout: 0

09-18 10:13:33.889 1386-1386/com.sleep.sunshine I/TestTouchEventLayout: onTouchEvent: 0

3、将MyLayout的onFilterTouchEventForSecurity 方法里直接返回false

09-18 10:16:46.071 4555-4555/com.sleep.sunshine I/TestTouchEventLayout: dispatchTouchEvent: 0

09-18 10:16:46.071 4555-4555/com.sleep.sunshine I/TestTouchEventLayout: onFilterTouchEventForSecurity:

3、将MyLayout的dispatchTouchEvent方法里返回true / false

@Override

public boolean dispatchTouchEvent(MotionEvent ev) {

Log.i(TAG, "dispatchTouchEvent: "+ev.getAction());

// return super.dispatchTouchEvent(ev);

return true/false;

}

//true

09-18 10:18:07.333 5480-5480/com.sleep.sunshine I/TestTouchEventLayout: dispatchTouchEvent: 0

//false

09-18 10:18:07.333 5480-5480/com.sleep.sunshine I/TestTouchEventLayout: dispatchTouchEvent: 0

09-18 10:18:07.362 5480-5480/com.sleep.sunshine I/TestTouchEventLayout: dispatchTouchEvent: 2

09-18 10:18:07.380 5480-5480/com.sleep.sunshine I/TestTouchEventLayout: dispatchTouchEvent: 1

4、总结流程图如下:

Layout 的dispatchTouchEvent -> Layout的onFilterTouchEventForSecurity -> Button的dispatchTouchEvent -> Button的onFilterTouchEventForSecurity

31e20def82c2

2428413-74c2fff552c0e43b.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值