Android 触摸事件流程分析

在处理触摸事件是,经常会发现触摸事件没有反映。

这里通过增加Log的方式,实践地进行触摸事件的跟踪

  • 查考触摸事件分发到哪个Window

参考下边的链接,可以知道,窗口在Android中,以Window类形式出现,系统通过inputFlinger将触摸事件发送的Window中。

所以首先在inputFlinger中增加对按下事件处理的Log。

inputFlinger中,当按下时,会开始查找合适的窗口。当然,只能由一个Window实例进行处理(从代码看是如此)。之后的滑动到手指离开屏幕之前,都是这个Widnow。当然肯定会有例外情况,这里未具体看。

frameworks/native/services/inputflinger/InputDispacher.cpp

int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
        const MotionEntry* entry, Vector& inputTargets, nsecs_t* nextWakeupTime,
        bool* outConflictingPointerActions) {
    ... ...
    if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
        /* Case 1: New splittable pointer going down, or need target for hover or scroll. */
    ... ...
        // Traverse windows from front to back to find touched window and outside targets.
        size_t numWindows = mWindowHandles.size();
        for (size_t i = 0; i < numWindows; i++) {
        ... ...
        }
        // 这里,增加Log,打印出来点击按下时,处理事件的窗口。
        if (newTouchedWindowHandle != NULL) {
            ALOGI("Vigi Event Process Window is %s", newTouchedWindowHandle->getName().c_str());
        }
}

编译/system/lib64/libinputflinger.so 执行后,打印的Log如下:

可以看到在桌面,通知栏,底部导航栏上的点下Log信息。通过这个,可以分析框架点击事件,是否分发给了对应的Window。

01-13 11:36:06.733: I/InputDispatcher(922): Vigi Event Process Window is Window{c578ed1 u0 com.android.launcher3/com.android.launcher3.Launcher}
01-13 11:36:10.724: I/InputDispatcher(922): Vigi Event Process Window is Window{e7bae42 u0 StatusBar}
01-13 11:36:12.692: I/InputDispatcher(922): Vigi Event Process Window is Window{3658693 u0 NavigationBar}

在app进程中,查看接收到的事件,在分发之前

如果上边只是说明了inputflinger将事件通过通道发送了出去,那么下边位置增加Log打印,就可以知道应用中是否接收到了事件

在frameworks/base/core/java/android/view/ViewRootImpl.java文件中,

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

        @Override
        public void onInputEvent(InputEvent event, int displayId) {
            /// M: record current key event and motion event to dump input event info for
            /// ANR analysis. {
            ViewDebugManager.getInstance().debugInputEventStart(event);
            /// }
            // 这里增加Log打印,输入当前通道的名称,就可以知道是否是自己关心的应用了
            android.util.Log.d("vigi", "Channel is " + (mInputChannel != null ? mInputChannel.getName() : "NULL"));
            enqueueInputEvent(event, this, 0, true);
        }

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

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

输出的结果如下:

我写了三个例子,

01-13 15:19:23.511: D/vigi(1435): Channel is a5d9e1 NavigationBar (client)
01-13 15:19:23.511: D/vigi(1435): Channel is 3f21987 StatusBar (client)
01-13 15:19:23.510: D/vigi(4159): Channel is e64dc99 cn.dida.wordgames2/cn.dida.wordgames2.articalgame.ArticalMainActivity (client)
 

在Activity上,接收触摸事件

如果上边的事件正确传递,会进入Activity的dispatchTouchEvent中。

	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		Log.d("vigi", "dispatchTouchEvent ev = " + ev);
		return super.dispatchTouchEvent(ev);
	}

后边事件会分发给具体的View,所以在需要分析,就是纯的界面相关的流程了。

参考:

https://www.jianshu.com/p/f05d6b05ba17

你可能感兴趣的:(Android开发)