怎么看android底层源码,从底层源码分析Android事件传递机制

点击一下告诉你什么是事件分发,知其然知其所以然,所以这边我篇我们就对源码展开分析!

我们知道事件都是由Activity往下面分发的!但是Activity.dispatchTouchEvent()又是从被哪里调用的呢?好奇不好奇?

1.首先从手指触摸到屏幕开始

我们知道Android是基于Linux系统的。当输入设备可用时(这里的输入设备包括很多设备,比如触摸屏和键盘是Android最普遍也是最标准的输入设备,另外它还包括外接的游戏手柄、鼠标等),Linux内核会为输入设置创建对应的设备节点。当输入设备不可用时,就把对应的设备节点删除,这也是如果我们的屏幕意外摔碎了或者其他原因导致触摸屏幕不可用时触摸没有反应的根本原因。当我们的输入设备可用时(我们这里只来讲解触摸屏),我们对触摸屏进行操作时,Linux就会收到相应的硬件中断,然后将中断加工成原始的输入事件并写入相应的设备节点中。而我们的Android 输入系统所做的事情概括起来说就是**监控这些设备节点,当某个设备节点有数据可读时,将数据读出并进行一系列的翻译加工,然后在所有的窗口中找到合适的事件接收者,并派发给它。

手指进行一系列操作(这里指的是手指的移动,这一步可能没有)

手指抬起或者因其他其他原因(突然间来了个电话之类的)导致事件结束

上面我们说到了Android 输入系统所做的事情概括起来说就是监控设备节点,当某个设备节点有数据可读时,将数据读出并进行一系列的翻译加工,然后在所有的窗口中找到合适的事件接收者,并派发给它。那么它是如何做的呢,,我们来具体分析一下。Android 的输入系统InputManagerService(以下简称为IMS)作为系统服务,它像其他系统服务一样在SystemServer进程中创建。

Linux会为所有可用的输入设备在/dev/input目录在建立event0~n或者其他名称的设备节点,Android输入系统会监控这些设备节点,具体是通过INotify和Epoll机制来进行监控。而不是通过一个线程进行轮询查询。

INotify机制

INotify是Linux内核提供的一种文件系统变化通知机制。它可以为应用程序监控文件系统的变化,如文件的新建,删除等。

//创建INotify对象,并用描述符inotifyFd 描述它

int inotifyFd = inotify_init();

/*

添加监听

inotify_add_watch函数参数说明

inotifyFd:上面建立的INotify对象的描述符,当监听的目录或文件发生变化时记录在INotify对象

“/dev/input”:被监听的文件或者目录

IN_CREATE | IN_DELETE:事件类型

综合起来下面的代码表示的意思就是当“/dev/input”下发生IN_CREATE | IN_DELETE(创建或者删除)时即把这个事件写入到INotify对象中

*/

int wd = inotify_add_watch(inotifyFd, "/dev/input", IN_CREATE|IN_DELETE )

Epoll机制

在上述INotify机制中我们知道了我们只需关心inotifyFd这个描述符就行了,可是事件是随机发生的,我们也不会本末倒置的采用轮询的方式轮询这个描述符,因为如果这样做的话会浪费大量系统资源。这时候我们Linux的另一个机制就派上用场了,即Epoll机制。Epoll机制简单的说就是使用一次等待来获取多个描述的可读或者可写状态。这样我们不必对每一个描述符创建独立的线程进行阻塞读取,在避免了资源浪费的同时获得较快的相应速度。

至此原始输入事件已经读取完毕,Android输入系统对原始输入事件进行翻译加工以及派发的详细过程很复杂。我们这里只分析其中一部分——IMS与窗口。

Avtivity,Window,PhoneWindow,以及ViewRootImpl之间的联系

上文中我们也说到了IMS会在所有的窗口中找到合适的事件接收者。IMS是运行在SystemServer进程中,而我们的窗口呢,是在我们的应用进程中。这就引出了我们在上文中留下的悬念

// ② 初始化mInputChanel。InputChannel是窗口接收来自InputDispatcher的输入事件的管道。这部分内容我们将在下一篇介绍。

if ((mWindowAttributes.inputFeatures

& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {

mInputChannel = new InputChannel();

}

...

...

// ③ 如果mInputChannel不为空,则创建mInputEventReceiver用于接收输入事件。

if (mInputChannel != null) {

mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,

Looper.myLooper());

}

InputChannel

InputChannel的本质是一对SocketPair(非网络套接字)。套接字可以用于网络通信,也可以用于本机内的进程通信。进程间通信的一种方式

public final class InputChannel implements Parcelable {

private static final String TAG = "InputChannel";

private static final boolean DEBUG = false;

public static final Parcelable.Creator CREATOR

= new Parcelable.Creator() {

public InputChannel createFromParcel(Parcel source) {

InputChannel result = new InputChannel();

result.readFromParcel(source);

return result;

}

public InputChannel[] newArray(int size) {

return new InputChannel[size];

}

};

@SuppressWarnings("unused")

private long mPtr; // used by native code

private static native InputChannel[] nativeOpenInputChannelPair(String name);

private native void nativeDispose(boolean finalized);

private native void nativeTransferTo(InputChannel other);

private native void nativeReadFromParcel(Parcel parcel);

private native void nativeWriteToParcel(Parcel parcel);

private native void nativeDup(InputChannel target);

private native String nativeGetName();

}

WindowInputEventReceiver

得到InputChannel后,便用它创建WindowInputEventReceiver,WindowInputEventReceiver继承于InputEventReceiver,InputEventReceiver对象可以接收来自InputChannel的输入事件,并触发其onInputEvent方法的回调。我们这里的是WindowInputEventReceiver,所以我们来看一下这个类

final class WindowInputEventReceiver extends InputEventReceiver {

public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {

super(inputChannel, looper);

}

@Override

public void onInputEvent(InputEvent event, int displayId) {

enqueueInputEvent(event, this, 0, true);

}

@Override

public void onBatchedInputEventPending() {

if (mUnbufferedInputDispatch) {

super.onBatchedInputEventPending();

} else {

scheduleConsumeBatchedInput();

}

}

@Override

public void dispose() {

unscheduleConsumeBatchedInput();

super.dispose();

}

}

enqueueInputEvent

void enqueueInputEvent(InputEvent event,

InputEventReceiver receiver, int flags, boolean processImmediately) {

...

//① 将InputEvent对应的InputEventReceiver封装为一个QueuedInputEvent

QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);

//② 将新建的QueuedInputEvent 追加到mPendingInputEventTail所表示的一个单向链表中

QueuedInputEvent last = mPendingInputEventTail;

if (last == null) {

mPendingInputEventHead = q;

mPendingInputEventTail = q;

} else {

last.mNext = q;

mPendingInputEventTail = q;

}

mPendingInputEventCount += 1;

if (processImmediately) {

//③ 如果第三个参数为true,则直接在当前线程中开始对输入事件的处理工作

doProcessInputEvents();

} else {

//④ 否则将处理事件的请求发送给主线程的Handler,随后进行处理

scheduleProcessInputEvents();

}

doProcessInputEvents

void doProcessInputEvents() {

//遍历整个输入事件队列,并逐一处理

while (mPendingInputEventHead != null) {

QueuedInputEvent q = mPendingInputEventHead;

mPendingInputEventHead = q.mNext;

if (mPendingInputEventHead == null) {

mPendingInputEventTail = null;

}

q.mNext = null;

mPendingInputEventCount -= 1;

Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,

mPendingInputEventCount);

long eventTime = q.mEvent.getEventTimeNano();

long oldestEventTime = eventTime;

if (q.mEvent instanceof MotionEvent) {

MotionEvent me = (MotionEvent)q.mEvent;

if (me.getHistorySize() > 0) {

oldestEventTime = me.getHistoricalEventTimeNano(0);

}

}

mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);

deliverInputEvent()//方法会将完成单个事件的整个处理流程

deliverInputEvent

private void deliverInputEvent(QueuedInputEvent q) {

Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",

q.mEvent.getSequenceNumber());

if (mInputEventConsistencyVerifier != null) {

mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);

}

InputStage stage;

if (q.shouldSendToSynthesizer()) {

stage = mSyntheticInputStage;

} else {

stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;

}

if (q.mEvent instanceof KeyEvent) {

mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);

}

if (stage != null) {

handleWindowFocusChanged();

stage.deliver(q);

} else {

finishInputEvent(q);

}

}

new ViewPostImeInputStage(mSyntheticInputStage);

从这个方法processPointerEvent将事件传递给了View树的根节点,调用了mView.dispatchPointerEvent(event);

private int processPointerEvent(QueuedInputEvent q) {

final MotionEvent event = (MotionEvent)q.mEvent;

mAttachInfo.mUnbufferedDispatchRequested = false;

mAttachInfo.mHandlingPointerEvent = true;

// 此时ViewRootImpl会将事件的处理权移交给View树的根节点,调用dispatchPointerEvent函数

boolean handled = mView.dispatchPointerEvent(event);

maybeUpdatePointerIcon(event);

maybeUpdateTooltip(event);

mAttachInfo.mHandlingPointerEvent = false;

if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {

mUnbufferedInputDispatch = true;

if (mConsumeBatchedInputScheduled) {

scheduleConsumeBatchedInputImmediately();

}

}

return handled ? FINISH_HANDLED : FORWARD;

}

这里肯定有疑问了,为什么会传到mView.dispatchPointerEvent(event),不应该先到Activity.dispatchPointerEvent(event)?

DecorView.dispatchTouchEvent(MotionEvent ev)

@Override

public boolean dispatchTouchEvent(MotionEvent ev) {

final Window.Callback cb = mWindow.getCallback();

return cb != null && !mWindow.isDestroyed() && mFeatureId < 0

? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);

}

Window.Callback cb = mWindow.getCallback();这个是Activity里面实现的

final void attach(Context context, ActivityThread aThread,

Instrumentation instr, IBinder token, int ident,

Application application, Intent intent, ActivityInfo info,

CharSequence title, Activity parent, String id,

NonConfigurationInstances lastNonConfigurationInstances,

Configuration config, String referrer, IVoiceInteractor voiceInteractor,

Window window, ActivityConfigCallback activityConfigCallback) {

mWindow = new PhoneWindow(this, window, activityConfigCallback);

mWindow.setWindowControllerCallback(this);

mWindow.setCallback(this);

}

Activity在这里实现了Window.Callback

public class Activity extends ContextThemeWrapper

implements LayoutInflater.Factory2,

Window.Callback,

}

public interface Callback {

public boolean dispatchTouchEvent(MotionEvent event);

}

简单暴力查看

de649f1f45cf

image.png

总结下!

1.当我们触摸屏幕时,通过INotify机制&Epoll机制改变和发送给WindowInputEventReceiver。

2.WindowInputEventReceiver是ViewRootImpl的内部类,通过enqueueInputEvent方法,将输入事件加入输入事件队列中,并进行处理和转发。

3.ViewPostImeInputStage收到输入事件,将事件传递给DecorView的dispatchPointerEvent()方法(是View的方法)

4.dispatchPointerEvent()方法通过DecorView中的dispatchTouchEvent()方法,调用了Activity的dispatchTouchEvent()方法。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值