那天有人问我,Android 的事件到底是怎么来的?

CharSequence title, Activity parent, String id,

NonConfigurationInstances lastNonConfigurationInstances,

Configuration config, String referrer, IVoiceInteractor voiceInteractor,

Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {

attachBaseContext(context);

mFragments.attachHost(null /parent/);

//PhoneWindow初始化

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

mWindow.setWindowControllerCallback(mWindowControllerCallback);

mWindow.setCallback(this);

mWindow.setOnWindowDismissedCallback(this);

mWindow.getLayoutInflater().setPrivateFactory(this);

2.ActivityThread.handleResumeActivity() 通过PhoneWindow获取DecorView,然后调用activity.makeVisible()

public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,

String reason) {

if (r.window == null && !a.mFinished && willBeVisible) {

r.window = r.activity.getWindow();

View decor = r.window.getDecorView();

decor.setVisibility(View.INVISIBLE);

ViewManager wm = a.getWindowManager();

WindowManager.LayoutParams l = r.window.getAttributes();

a.mDecor = decor;

l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;

if (a.mVisibleFromClient) {

if (!a.mWindowAdded) {

a.mWindowAdded = true;

wm.addView(decor, l);

} else {

a.onWindowAttributesChanged(l);

}

}

} else if (!willBeVisible) {

if (localLOGV) Slog.v(TAG, “Launch " + r + " mStartedActivity set”);

r.hideForNow = true;

}

if (r.activity.mVisibleFromClient) {

r.activity.makeVisible();

}

}

}

2.1 PhoneWindow创建DecorView的过程

@Override

public final @NonNull View getDecorView() {

if (mDecor == null || mForceDecorInstall) {

//组装DecorView

installDecor();

}

return mDecor;

}

private void installDecor() {

mForceDecorInstall = false;

if (mDecor == null) {

//获取DecorView

mDecor = generateDecor(-1);

mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);

mDecor.setIsRootNamespace(true);

if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {

mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);

}

}

}

//返回值就是DecorView

protected DecorView generateDecor(int featureId) {

// System process doesn’t have application context and in that case we need to directly use

// the context we have. Otherwise we want the application context, so we don’t cling to the

// activity.

Context context;

if (mUseDecorContext) {

Context applicationContext = getContext().getApplicationContext();

if (applicationContext == null) {

context = getContext();

} else {

context = new DecorContext(applicationContext, this);

if (mTheme != -1) {

context.setTheme(mTheme);

}

}

} else {

context = getContext();

}

return new DecorView(context, featureId, this, getAttributes());

}

2.2. activity.makeVisible()过程

void makeVisible() {

if (!mWindowAdded) {

ViewManager wm = getWindowManager();

//此时调用的其实事WindowManager.addView()

wm.addView(mDecor, getWindow().getAttributes());

mWindowAdded = true;

}

mDecor.setVisibility(View.VISIBLE);

}

3. WindowManager是接口,找到其实现类并调用WindowManagerImpl.addView()

@Override

public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {

applyDefaultToken(params);

//此时调用的是WindowManagerGlobal.addView()

mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,

mContext.getUserId());

}

4. WindowManagerGlobal.addView() 初始化ViewRootImpl,然后调用root.setView()

public void addView(View view, ViewGroup.LayoutParams params,

Display display, Window parentWindow, int userId) {

synchronized (mLock) {

//初始化ViewRootImpl

root = new ViewRootImpl(view.getContext(), display);

view.setLayoutParams(wparams);

mViews.add(view);

mRoots.add(root);

mParams.add(wparams);

// do this last because it fires off messages to start doing things

try {

root.setView(view, wparams, panelParentView, userId);

} catch (RuntimeException e) {

// BadTokenException or InvalidDisplayException, clean up.

if (index >= 0) {

removeViewLocked(index, true);

}

throw e;

}

}

}

5. ViewRootImpl.setView(view,…,…) 创建InputChannel, InputQueue, WindowInputEventReceiver

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, int userId) {

synchronized (this) {

if (mView == null) {

mView = view;

// Schedule the first layout -before- adding to the window

// manager, to make sure we do the relayout before receiving

// any other events from the system.

requestLayout();

InputChannel inputChannel = null;

if ((mWindowAttributes.inputFeatures

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

inputChannel = new InputChannel();

}

if (inputChannel != null) {

if (mInputQueueCallback != null) {

//创建对象

mInputQueue = new InputQueue();

mInputQueueCallback.onInputQueueCreated(mInputQueue);

}

mInputEventReceiver = new WindowInputEventReceiver(inputChannel,

Looper.myLooper());

}

}

}

6. 其实Android事件的源头来自于用户输入行为,由硬件进行捕获,一般会保存在 dev/input 节点下,后续组装成KeyEvent/MotionEvent对象,经Native进入Java的InputEventReceiver.dispatchInputEvent()中。

我们先分析InputEventReceiver

private void dispatchInputEvent(int seq, InputEvent event) {

mSeqMap.put(event.getSequenceNumber(), seq);

onInputEvent(event);

}

public void onInputEvent(InputEvent event) {

finishInputEvent(event, false);

}

由于InputEventReceiver是abstract类,因此需要找到对应的实现类,此时第5步中 WindowInputEventReceiver 即是实现类,因此找到重写的onInputEvent()方法进行下一步分析。

7. ViewRootImpl.WindowInputEventReceiver extends InputEventReceiver,连带调用了enqueueInputEvent()->doProcessInputEvents-> deliverInputEvent(q),方法中获取到mFirstPostImeInputStage对象其实为ViewPostImeInputStage。

@Override

public void onInputEvent(InputEvent event) {

Trace.traceBegin(Trace.TRACE_TAG_VIEW, “processInputEventForCompatibility”);

List processedEvents;

try {

processedEvents =

mInputCompatProcessor.processInputEventForCompatibility(event);

} finally {

Trace.traceEnd(Trace.TRACE_TAG_VIEW);

}

if (processedEvents != null) {

if (processedEvents.isEmpty()) {

// InputEvent consumed by mInputCompatProcessor

finishInputEvent(event, true);

} else {

for (int i = 0; i < processedEvents.size(); i++) {

enqueueInputEvent(

processedEvents.get(i), this,

QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY, true);

}

}

} else {

enqueueInputEvent(event, this, 0, true);

}

}

void enqueueInputEvent(InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately) {

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

// Always enqueue the input event in order, regardless of its time stamp.

// We do this because the application or the IME may inject key events

// in response to touch events and we want to ensure that the injected keys

// are processed in the order they were received and we cannot trust that

// the time stamp of injected events are monotonic.

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();

}

}

void doProcessInputEvents() {

// Deliver all pending input events in the queue.

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(q);

}

// We are done processing all input events that we can process right now

// so we can clear the pending flag immediately.

if (mProcessInputEventsScheduled) {

mProcessInputEventsScheduled = false;

mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);

}

}

private void deliverInputEvent(QueuedInputEvent q) {

try {

InputStage stage;

if (q.shouldSendToSynthesizer()) {

stage = mSyntheticInputStage;

} else {

//此时返回两个InputStage类型的对象,这个InputStage为abstract因此需要找对应的实现类。

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

}

if (q.mEvent instanceof KeyEvent) {

Trace.traceBegin(Trace.TRACE_TAG_VIEW, “preDispatchToUnhandledKeyManager”);

try {

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

} finally {

Trace.traceEnd(Trace.TRACE_TAG_VIEW);

}

}

if (stage != null) {

handleWindowFocusChanged();

stage.deliver(q);

} else {

finishInputEvent(q);

}

} finally {

Trace.traceEnd(Trace.TRACE_TAG_VIEW);

}

}

此时需要注意这个InputStage 的实现类相对比较多,不过可以重点看下setView()方法的末尾,着重看mFirstPostImeInputStage赋值逻辑。

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, int userId) {

// Set up the input pipeline.

CharSequence counterSuffix = attrs.getTitle();

mSyntheticInputStage = new SyntheticInputStage();

//最终new了ViewPostImeInputStage

InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);

//继续看viewPostImeStage赋值

InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,

“aq:native-post-ime:” + counterSuffix);

//初始化并传入nativePostImeStage,需要查看nativePostImeStage赋值逻辑,继续往上看。

InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);

InputStage imeStage = new ImeInputStage(earlyPostImeStage,

“aq:ime:” + counterSuffix);

InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);

InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,

“aq:native-pre-ime:” + counterSuffix);

mFirstInputStage = nativePreImeStage;

//这是赋值位置,可以看以上逻辑是怎么赋值earlyPostImeStage对象

mFirstPostImeInputStage = earlyPostImeStage;

mPendingInputEventQueueLengthCounterName = “aq:pending:” + counterSuffix;

if (mView instanceof RootViewSurfaceTaker) {

PendingInsetsController pendingInsetsController =

((RootViewSurfaceTaker) mView).providePendingInsetsController();

if (pendingInsetsController != null) {

pendingInsetsController.replayAndAttach(mInsetsController);

}

}

}

通过以上逻辑可以清晰地看到mFirstPostImeInputStage 即是ViewPostImeInputStage,我们需要跟进ViewPostImeInputStage看下对应的onProcess()方法。

final class ViewPostImeInputStage extends InputStage {

public ViewPostImeInputStage(InputStage next) {

super(next);

}

@Override

protected int onProcess(QueuedInputEvent q) {

if (q.mEvent instanceof KeyEvent) {

return processKeyEvent(q);

} else {

final int source = q.mEvent.getSource();

if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {

return processPointerEvent(q);

} else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {

return processTrackballEvent(q);

} else {

return processGenericMotionEvent(q);

}

}

}

}

以上逻辑中先判断了输入事件是键盘,还是触摸,触摸逻辑中又判断了输入源是屏幕还是trackball(我猜测这判断的是鼠标等设备输入),不过不重要,我们主要看屏幕输入的逻辑,也就是processPointerEvent(q);方法

private int processPointerEvent(QueuedInputEvent q) {

final MotionEvent event = (MotionEvent)q.mEvent;

mAttachInfo.mUnbufferedDispatchRequested = false;

《设计思想解读开源框架》

第一章、 热修复设计

  • 第一节、 AOT/JIT & dexopt 与 dex2oat

  • 第二节、 热修复设计之 CLASS_ISPREVERIFIED 问题

  • 第三节、热修复设计之热修复原理

  • 第四节、Tinker 的集成与使用(自动补丁包生成)

    第二章、 插件化框架设计

  • 第一节、 Class 文件与 Dex 文件的结构解读

  • 第二节、 Android 资源加载机制详解

  • 第三节、 四大组件调用原理

  • 第四节、 so 文件加载机制

  • 第五节、 Android 系统服务实现原理

    第三章、 组件化框架设计

  • 第一节、阿里巴巴开源路由框——ARouter 原理分析

  • 第二节、APT 编译时期自动生成代码&动态类加载

  • 第三节、 Java SPI 机制

  • 第四节、 AOP&IOC

  • 第五节、 手写组件化架构

    第四章、图片加载框架

  • 第一节、图片加载框架选型

  • 第二节、Glide 原理分析

  • 第三节、手写图片加载框架实战

    第五章、网络访问框架设计

  • 第一节、网络通信必备基础

  • 第二节、OkHttp 源码解读

  • 第三节、Retrofit 源码解析

    第六章、 RXJava 响应式编程框架设计

  • 第一节、链式调用

  • 第二节、 扩展的观察者模式

  • 第三节、事件变换设计

  • 第四节、Scheduler 线程控制

    第七章、 IOC 架构设计

  • 第一节、 依赖注入与控制反转

  • 第二节、ButterKnife 原理上篇、中篇、下篇

  • 第三节、Dagger 架构设计核心解密

    第八章、 Android 架构组件 Jetpack

  • 第一节、 LiveData 原理

  • 第二节、 Navigation 如何解决 tabLayout 问题

  • 第三节、 ViewModel 如何感知 View 生命周期及内核原理

  • 第四节、 Room 架构方式方法

  • 第五节、 dataBinding 为什么能够支持 MVVM

  • 第六节、 WorkManager 内核揭秘

  • 第七节、 Lifecycles 生命周期


    本文包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…

    《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
    第二节、OkHttp 源码解读

  • 第三节、Retrofit 源码解析

    [外链图片转存中…(img-PzQ1Moay-1715418930312)]

    第六章、 RXJava 响应式编程框架设计

  • 第一节、链式调用

  • 第二节、 扩展的观察者模式

  • 第三节、事件变换设计

  • 第四节、Scheduler 线程控制

    [外链图片转存中…(img-lHsMX35U-1715418930312)]

    第七章、 IOC 架构设计

  • 第一节、 依赖注入与控制反转

  • 第二节、ButterKnife 原理上篇、中篇、下篇

  • 第三节、Dagger 架构设计核心解密

    [外链图片转存中…(img-21SIzr69-1715418930313)]

    第八章、 Android 架构组件 Jetpack

  • 第一节、 LiveData 原理

  • 第二节、 Navigation 如何解决 tabLayout 问题

  • 第三节、 ViewModel 如何感知 View 生命周期及内核原理

  • 第四节、 Room 架构方式方法

  • 第五节、 dataBinding 为什么能够支持 MVVM

  • 第六节、 WorkManager 内核揭秘

  • 第七节、 Lifecycles 生命周期

    [外链图片转存中…(img-tEAo21qN-1715418930313)]
    本文包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…
    [外链图片转存中…(img-eJljqjH7-1715418930314)]
    《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值