Android事件传递机制

来源:互联网 发布:mac书名号怎么打出来 编辑:程序博客网 时间:2024/05/21 06:15

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 0