Android高级UI面试题汇总(含详细解析 十一)

Android并发编程高级面试题汇总最全最细面试题讲解持续更新中👊👊
👀你想要的面试题这里都有👀
👇👇👇

事件冲突怎么解决?

这道题想考察什么?

这道题想考察同学对事件冲突的解决是否掌握了,这个问题也是同样也是开发中最常遇到的问题。

考生应该如何回答

事件冲突的解决办法分两种:内部拦截法和外部拦截法。

内部拦截法

首先我们来介绍下内部拦截法。它的处理方式是:

第一块代码
// 子View中添加如下代码:
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
    int x = (int) event.getX();
    int y = (int) event.getY();

    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            getParent().requestDisallowInterceptTouchEvent(true);
            break;
        }
        case MotionEvent.ACTION_MOVE: {
            int deltaX = x - mLastX;
            int deltaY = y - mLastY;
            // 1
            if (Math.abs(deltaX) > Math.abs(deltaY)) {
                getParent().requestDisallowInterceptTouchEvent(false);
            }
            break;
        }
        case MotionEvent.ACTION_UP: {
            break;
        }
        default:
            break;
    }

    mLastX = x;
    mLastY = y;
    return super.dispatchTouchEvent(event);
}
第二块代码
// 父容器中添加如下代码
public boolean onInterceptTouchEvent(MotionEvent event) {
    // 1
    if (event.getAction() == MotionEvent.ACTION_DOWN){
        super.onInterceptTouchEvent(event);
        return false;
    }
    return true;
}

首先我们介绍子View中添加的代码,getParent().requestDisallowInterceptTouchEvent(true)的作用,它的代码如下:

第三块代码
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
  if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
    // We're already in this state, assume our ancestors are too
    return;
  }

  if (disallowIntercept) {
    mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
  } else {
    mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
  }

  // Pass it up to our parent
  if (mParent != null) {
    mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
  }
}

可以看出,通过方法参数disallowIntercept的值,控制了mGroupFlags的值,而这个值是控制父容器是否可以拦截子View的关键代码,如下:

第四块代码
public boolean dispatchTouchEvent(MotionEvent ev) {
  if (actionMasked == MotionEvent.ACTION_DOWN
      || mFirstTouchTarget != null) {
    // 1
    final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
    // 2
    if (!disallowIntercept) {
      intercepted = onInterceptTouchEvent(ev);
      ev.setAction(action); // restore action in case it was changed
    } else {
      intercepted = false;
    }
  } else {
    // There are no touch targets and this action is not an initial down
    // so this view group continues to intercept touches.
    intercepted = true;
  }
}

通过代码1和2可以知道,当调用 requestDisallowInterceptTouchEvent 传入参数 true 时,disallowIntercept 为 true,就会导致 intercepted = false,从而父容器事件必须要分发给子View。
那父容器中添加的代码是干什么呢?这就要说到事件冲突的解决思路了。我们知道一个事件只能由一个控件处理,而事件冲突实际上就是在不同情况下,按我们的需求分配事件给对应的控件处理。例如:子View是左右滑动的,父容器是上下滑动的,那我们就希望当手指左右滑的时候是子View在动,上下滑的时候是父容器在动。
既然我们的 MotionEvent.ACTION_DOWN 事件是分发给 子View 的,说明事件是由子View根据情况分发的,这个对应的就是 第一块代码的标记1处,此处根据水平和垂直滑动的距离判断出用户是在水平滑动还是垂直滑动。如果事件需要给父容器,则设置 requestDisallowInterceptTouchEvent(false)。然后结合第二块代码中的 onInterceptTouchEvent 返回 true,将分发给子View的事件抢过来,如何做到的呢?代码如下:

第五块代码
// 1
final boolean cancelChild = resetCancelNextUpFlag(target.child)
  || intercepted;
// 2
if (dispatchTransformedTouchEvent(ev, cancelChild, target.child, target.pointerIdBits)) {
  handled = true;
}
第六块代码
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
                                              View child, int desiredPointerIdBits) {
  final int oldAction = event.getAction();
  // 1
  if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
    event.setAction(MotionEvent.ACTION_CANCEL);
    if (child == null) {
      handled = super.dispatchTouchEvent(event);
    } else {
      handled = child.dispatchTouchEvent(event);
    }
    event.setAction(oldAction);
    return handled;
  }
}

第五块代码中的1处,因为 intercepted = true,所以cancelChild = true,从而会进入第六块代码1处,子View这个时候会执行 取消事件,将事件让出来,在下次MOVE事件处理时就会交给父容器处理。从而达到根据需求分配事件的要求。即解决了事件冲突。
那为什么我们还需要在第二块代码中添加标记1处的 if 判断语句呢?原因需要看如下代码:

第七块代码
public boolean dispatchTouchEvent(MotionEvent ev) {
  if (actionMasked == MotionEvent.ACTION_DOWN) {
    resetTouchState();
  }
}
private void resetTouchState() {
  mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
}

可以看到,resetTouchState 会重制 mGroupFlags 的值,而该代码在事件为 MotionEvent.ACTION_DOWN 的时候一定会执行。这就导致 disallowIntercept 在事件为 MotionEvent.ACTION_DOWN 的时候一定为 false,即 onInterceptTouchEvent 一定会执行。所以父容器只能在其他事件拦截子View。
外部拦截法的思路一样,在此就不赘述了。

外部拦截法

外部拦截法直接在父布局中判断是否需要自己处理该事件,如果达到自己需要拦截的条件,直接在onInterceptTouchEvent返回为true,中断该手势后续事件的下发,逻辑上更加简单。实例代码如下:

private int mLastXIntercept;
private int mLastYIntercept;
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
	int x = (int) event.getX();
	int y = (int) event.getY();
	final int action = event.getAction();
	switch (action) {
		case MotionEvent.ACTION_DOWN:
			mLastXIntercept = (int) event.getX();
			mLastYIntercept = (int) event.getY();
			break;
		case MotionEvent.ACTION_MOVE:
			if (needIntercept) {//判断是否需要拦截的条件
				return true;
			}
			break;
		case MotionEvent.ACTION_UP:
			break;
	}
	return super.onInterceptTouchEvent(event);
}

由于面试题内容比较多,篇幅有限,资料已经被整理成了PDF文档,有需要2023年Android中高级最全面试真题答案 完整文档的可扫描下方卡片免费获取~

PS:(文末还有使用ChatGPT机器人小福利哦!!大家不要错过)

目录

img

第一章 Java方面

  • Java基础部分
  • Java集合
  • Java多线程
  • Java虚拟机

img

第二章 Android方面

  • Android四大组件相关
  • Android异步任务和消息机制
  • Android UI绘制相关
  • Android性能调优相关
  • Android中的IPC
  • Android系统SDK相关
  • 第三方框架分析
  • 综合技术
  • 数据结构方面
  • 设计模式
  • 计算机网络方面
  • Kotlin方面

img

第三章 音视频开发高频面试题

  • 为什么巨大的原始视频可以编码成很小的视频呢?这其中的技术是什么呢?
  • 怎么做到直播秒开优化?
  • 直方图在图像处理里面最重要的作用是什么?
  • 数字图像滤波有哪些方法?
  • 图像可以提取的特征有哪些?
  • 衡量图像重建好坏的标准有哪些?怎样计算?

img

第四章 Flutter高频面试题

  • Dart部分
  • Flutter部分

img

第五章 算法高频面试题

  • 如何高效寻找素数
  • 如何运用二分查找算法
  • 如何高效解决雨水问题
  • 如何去除有序数组的重复元素
  • 如何高效进行模幂运算
  • 如何寻找最长回文子串

img

第六章 Andrio Framework方面

  • 系统启动流程面试题解析
  • Binder面试题解析
  • Handler面试题解析
  • AMS面试题解析

img

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值