Android系列之 屏幕触控机制(一)

目录

[1 Android native层传递点击事件](#1 Android native层传递点击事件)

[2 .Window和WindowManagerService的关系](#2 .Window和WindowManagerService的关系)

[2.1 ViewRootImpl 如何串联Window和WindowManagerService](#2.1 ViewRootImpl 如何串联Window和WindowManagerService)

[2.2 ViewRootImpl和Window的关系](#2.2 ViewRootImpl和Window的关系)

[2.3 ViewRootImpl和WindowManagerService的关系](#2.3 ViewRootImpl和WindowManagerService的关系)


以下章节待分解:

  1. ViewRootImpl的事件接收及分发

  2. ViewGroup事件的分发机制

4.1 activity的视图创建流程

4.2 ViewGroup的事件分发流程

4.3 View的事件处理

  1. 事件分发具体案例及解决方案

Android屏幕触控机制整体流程图

图1

1 Android native层传递点击事件

当用户点击屏幕时,屏幕会产生触摸事件,Linux内核会将触摸事件封装成event存到/dev/input/文件内。

inputReader从EventHub读取到事件并发送给InputDispatcher,

InputDispatcher分发至framework层 需要处理的地方。

下面我们来详细看一下framework层是如何接收点击事件并最终如何响应点击事件的

图2

2 .Window和WindowManagerService的关系

图3

2.1 ViewRootImpl 如何串联Window和WindowManagerService

当一个点击事件从native传递到framework时,viewRootImpl中的WindowInputEventReceiver()方法会最先响应点击事件。

而这个WindowInputEventReceiver()方法中的mInputChannel参数,是在WindowManagerService(以下简称wms )中和native层关联上的。

这个时候就有个疑问了,点击事件怎么和wms有关联了呢?其实wms他是一个重要的系统服务,用于窗口管理,他就是窗口的大主管,因为它记录了当前系统中所有窗口的完整信息,他还是点击事件的派发者,所以只有它才能判断出要把点击的事件投递给具体的某个应用进程进行处理。而应用进程如何接收的了?这里的应用进程可以理解成是一个应用层级的窗口Window。因为事件点击的目的地是应用层级的窗口Window。而wms和window中间需要一个纽带去衔接,这个中间的纽带就是ViewRootImpl, ViewRootImpl负责view 的绘制,也负责用户的点击操作处理。

下面就讲一下viewRootImp是如何创建并成为window和wms的纽带的。

2.2 ViewRootImpl和Window的关系

说起ViewRootImpl和window的关系,就要先看一下 ViewRootImpl是在哪里被创建的 ,这就要从handleResumeActivity流程开始看起

java 复制代码
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,String reason) {
        ......
    if (r.window == null && !a.mFinished && willBeVisible) {
        ......
    View decor = r.window.getDecorView();
        ......
    ViewManager wm = a.getWindowManager();
        ......
    wm.addView(decor, l);
        ......
}

wm.addView的wm的实例对象就是WindowManagerImpl,其中的参数decor是DecorView对象

接着看WindowManagerImpl的addView方法做了什么

java 复制代码
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}

又调用到了 WindowManagerGlobal的addView方法,可以看到ViewRootImpl在这里被创建了,并绑定了DecorView

java 复制代码
public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow) {
        ......
        root = new ViewRootImpl(view.getContext(), display);
         ......
        mViews.add(view);
        mRoots.add(root);
        mParams.add(wparams);
        root.setView(view, wparams, panelParentView);
        ......
}

2.2 ViewRootImpl和Window的关系

流程图大致介绍了ViewRootImpl是如何创建出来的,总结一下:在ActivityThread的handleResumeActivity()流程中,通过

WindowManager(WindowManagerImpl)的 addView() 实现了ViewRootImpl的创建。 此时我们应用层窗口Window就和ViewRootImpl建立了关联。

图4

2.3 ViewRootImpl和WindowManagerService的关系

而ViewRootImpl和wms的关联,是在ViewRootImpl的setview方法中

mWindowSession.addToDisplay()函数是添加窗口流程,对应的服务端就是WMS,而WMS又是个系统进程,所以这是个Binder跨进程调用方法,最终调用的是WMS的addWindow方法。而参数mInputChannel,它包括了发送和接收消息的功能封装。

最后声明了inputEvent方法,用来接受从底层传过来的点击事件

java 复制代码
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    synchronized (this) {
            ......

            requestLayout();
            if ((mWindowAttributes.inputFeatures
                    & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                mInputChannel = new InputChannel();
            }
            ......
            res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                        getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
                        mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                        mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
            ......

            if (mInputChannel != null) {

                    ... // 声明了inputEvent方法,用来接受从底层传过来的点击事件

                    mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
                            Looper.myLooper());
             }
}
相关推荐
阿巴斯甜4 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker5 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95276 小时前
Andorid Google 登录接入文档
android
黄林晴7 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab20 小时前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_1 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android