Android事件传递机制

1.本想从底层开始看看Android的事件是怎么产生的,怎么从底层传到window的,但是这里写图片描述 一位网友的总结:Linux Kernel将rawinputevent写入到设备节点后,InputReader会通过EventHub将原始事件读取出来并翻译加工为Android输入事件,而后把它交给InputDispatcher。InputDispatcher根据WMS(WindowManagerService)提供的窗口信息将事件传递给合适的窗口,若窗口为壁纸/SurfaceView等,则到了终点;否则会由该Window的ViewRoot继续分发到合适的View。

2.还是从window开始吧。当原始事件进入InputDispatcher时,已被加工为KeyEvent、MotionEvent(或SwitchEvent)。而后InputDispatcher会对事件进行进一步分发。
将事件放入派发队列

将输入事件加入到派发队列后,会依次执行以下步骤:

  • 派发线程开始派发事件;
  • 锁定目标窗口,然后向目标Window发送事件。
  • InputDispatcher通过InputChannel将event发给Window(InputDispatcher运行于system_server进程中,Window运行于应用进程,两者通过InputChannel通信。);
  • Window端的Looper被唤醒,从InputChannel中读取一个InputEvent,而后调用onInputEvent(ev)。具体来说是调用ViewRootImpl的mInputEventReceiver的成员的onInputEvent()方法。
  • 调用doProcessInputEvents()
  • 调用deliverInputEvent()

在Android系统中,对系统中的所有窗口进行管理是窗口管理服务WindowManagerService的职责(wms)。
在Android中界面的呈现是由Activity完成的
这里写图片描述
我们知道这个DecorView才是我们看到的显示界面 所以可以理解为用户的触摸按键的消息是由windowManagerService捕捉到然后交给phoneWindow中的DecorView进行相应的处理,而连接两者的桥梁则是一个ViewRoot类,ViewRoot类由windowManagerService创建。
这个ViewRoot可以

  • 向DecorView分发收到的用户发起的event事件,如按键,触屏,轨迹球等事件
  • 与WindowManagerService交互,完成整个Activity的GUI的绘制。

这里就不去谈Viewrootimpl是如何与WindowManagerService完成GUI的绘制了
在ViewRootImpl中包含有一个WindowInputEventReceiver对象,我们从名字都可以大致的知道它是一个接受用户事件的类,它是Viewrootimpl的一个内部类

final class WindowInputEventReceiver extends InputEventReceiver {
        public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
            super(inputChannel, looper);
        }

        @Override
        public void onInputEvent(InputEvent event) {
            enqueueInputEvent(event, this, 0, true);
        }

        @Override
        public void onBatchedInputEventPending() {
            if (mUnbufferedInputDispatch) {
                super.onBatchedInputEventPending();
            } else {
                scheduleConsumeBatchedInput();
            }
        }

        @Override
        public void dispose() {
            unscheduleConsumeBatchedInput();
            super.dispose();
        }
    }

我们来看看他是如何接受到事件,如何传递给DecorView的。
1 首先看看它老汉的构造方法:

 public InputEventReceiver(InputChannel inputChannel, Looper looper) {
 //... 省掉判断是否为null的方法
 // 用来传递消息
        mInputChannel = inputChannel;
        mMessageQueue = looper.getQueue();
        mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
                inputChannel, mMessageQueue);
        mCloseGuard.open("dispose");
    }

我们可以看出接受事件肯定和InputChannel,mMessageQueue相关(具体是什么关系下来在研究一下)

2 看看WindowInputEventReceiver中的方法

onInputEvent(InputEvent event)

该方法中调用了

void enqueueInputEvent(InputEvent event,
            InputEventReceiver receiver, int flags, boolean processImmediately) {
        adjustInputEventForCompatibility(event);
        QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
        QueuedInputEvent last = mPendingInputEventTail;
        if (last == null) {
            mPendingInputEventHead = q;
            mPendingInputEventTail = q;
        } else {
            last.mNext = q;
            mPendingInputEventTail = q;
        }
        mPendingInputEventCount += 1;
        Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
                mPendingInputEventCount);
        if (processImmediately) {
         // 立即处理事件
            doProcessInputEvents();
        } else {
         // 将事件放到队列的最后
            scheduleProcessInputEvents();
        }
    }

这俩种方式最后都会调用deliverInputEvent(QueuedInputEvent q)方法传送事件

Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
                q.mEvent.getSequenceNumber());
        if (mInputEventConsistencyVerifier != null) {
        //验证事件 根据不同的情况验证 onKeyEvent(keyEvent, nestingLevel);
        // onTouchEvent(motionEvent, nestingLevel); onGenericMotionEvent(motionEvent, //nestingLevel);onTrackballEvent(motionEvent, nestingLevel);
            mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
        }
        InputStage stage;
        if (q.shouldSendToSynthesizer()) {
        //从新输入事件处理输入事件
            stage = mSyntheticInputStage;
        } else {
        //ture?Performs early processing of post-ime input events:Delivers pre-ime //Finput events to a native activity* Does not support pointer events.
            stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
        }

        if (stage != null) {
            stage.deliver(q);
        } else {
            finishInputEvent(q);
        }

各种调用 最后调用InputMethodManager中的dispatchInputEvent方法 或者View.dispatchPointerEvent
终于跑到View上面来了!!!

public final boolean dispatchPointerEvent(MotionEvent event) {
        if (event.isTouchEvent()) {
            return dispatchTouchEvent(event);
        } else {
            return dispatchGenericMotionEvent(event);
        }
    }
onBatchedInputEventPending()
dispose()

事件在View上传递网上的资料有点多了 这里就暂时不去分析它了!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值