一、回顾
在分析touch事件分发源码前,我们先来了解Window.Callback, PhoneWindow, DecorView, ViewRootImpl 这几个类的数据流转。
1、Window.Callback是在Activity 的attach()方法中设置的
#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, IBinder assistToken) {
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
}
-------------------------------------------------------------------------
// PhoneWindow是Window的子类,故此调用window的setCallback方法
#PhoneWindow
private Callback mCallback;
public void setCallback(Callback callback) {
mCallback = callback;
}
2、通过ActivityThread.handleResumeActivity()流程中往下走,最终会发现DecorView传输到ViewRootImpl 的setView()方法中;mView则为DecorView
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
@UnsupportedAppUsage
View mView;
// view 为DecorView
synchronized (this) {
if (mView == null) {
mView = view;
}
}
}
3、我们都知道PhoneWindow中有DecorView,那是怎么初始化的,DecorView中含有的PhoneWindow又是如何添加的?继续往下看
**前提:**在Activity启动流程中我们知道在ActivityThread的performLaunchActivity的方法中调用了Activity的attach(),其中在attach()中创建了PhoneWindow()
那PhoneWindow中有DecorView是啥时候创建的呢?其实是在PhoneWindow的installDecor()中创建的,而installDecor()方法在多个地方呗调用到:
比如:
① Activity的 setContentView()方法,最终会调用到PhoneWindow的setContentView()方法, 此方法中调用到了installDecor();
② PhoneWindow的getDecorView()方法,如果获取mDecor为空,则调用installDecor()创建DecorView;
③ 还有很多地方调用到,详情请查看源码
public class PhoneWindow extends Window implements MenuBuilder.Callback {
private DecorView mDecor;
// 标注2️⃣
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
}
// 标注3️⃣
@Override
public final @NonNull View getDecorView() {
if (mDecor == null || mForceDecorInstall) {
installDecor();
}
return mDecor;
}
// 标注1️⃣
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
// 标注4️⃣
mDecor = generateDecor(-1);
} else {
// 标注7️⃣
mDecor.setWindow(this);
}
}
protected DecorView generateDecor(int featureId) {
Context context;
if (mUseDecorContext) {
Context applicationContext = getContext().getApplicationContext();
if (applicationContext == null) {
context = getContext();
} else {
context = new DecorContext(applicationContext, getContext());
if (mTheme != -1) {
context.setTheme(mTheme);
}
}
} else {
context = getContext();
}
// 标注5️⃣
return new DecorView(context, featureId, this, getAttributes());
}
}
-----------------------------------------------------------------------------
public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
private PhoneWindow mWindow;
DecorView(Context context, int featureId, PhoneWindow window,
WindowManager.LayoutParams params) {
...
// 标注6️⃣
setWindow(window);
...
}
void setWindow(PhoneWindow phoneWindow) {
// 标注8️⃣
mWindow = phoneWindow;
Context context = getContext();
if (context instanceof DecorContext) {
DecorContext decorContext = (DecorContext) context;
decorContext.setPhoneWindow(mWindow);
}
}
}
标注1️⃣:installDecor()方法中,mDecor 为空则调用generateDecor()方法去创建DecorView ,在DecorView 的构造方法中调用setWindow()方法;如果mDecor 不为空,则直接调用DecorView 的setWindow()方法;
标注2️⃣3️⃣:setContentView()方法和getDecorView()方法都调用到installDecor()方法,上面的介绍用举列子讲到;
标注4️⃣:调用generateDecor()方法去创建DecorView;
标注5️⃣:创建DecorView;
标注6️⃣:在DecorView的构造方法中调用setWindow,把PhoneWindow对象传入;
标注7️⃣:mDecor 不为空,直接调用DecorView 的setWindow()方法传入PhoneWindow对象;
标注8️⃣:把传入的PhoneWindow对象存入为全局变量,以便之后调用;
二、跟踪ViewRootImpl 的 setView 方法去找事件分发的起源
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
// view 为DecorView
...
// 标注1️⃣
requestLayout();
...
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
// 标注2️⃣
mInputChannel = new InputChannel();
}
try {
...
// 标注3️⃣
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
mTempInsets);
...
} catch (RemoteException e) {
...
}
...
if (view instanceof RootViewSurfaceTaker) {
mInputQueueCallback =
((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
}
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
// 标注4️⃣
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
}
...
}
标注1️⃣:最终会调用performtraversal() 方法,然后这个方法里面依次调用了 performMeasure(),performLayout(), performDraw() ,对应View里面的方法是measure() ,layout() ,draw();
标注2️⃣:包含发送和接收消息的功能封装
标注3️⃣:通过Binder调用,最终进入系统进程的Session,调用WMS的addWindow()方法
标注4️⃣:创建事件输入处理接收者
三、跟踪IWindowSession调用addToDisplay()方法,最终是怎么调用到WMS的addWindow()方法
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
final IWindowSession mWindowSession;
...
public ViewRootImpl(Context context, Display display) {
mContext = context;
// 标注2️⃣
mWindowSession = WindowManagerGlobal.getWindowSession();
...
}
...
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
...
// 标注1️⃣
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
mTempInsets);
...
}
}
-----------------------------------------------------------------------------
public final class WindowManagerGlobal {
private static IWindowManager sWindowManagerService;
@UnsupportedAppUsage
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
...
// 标注3️⃣
IWindowManager windowManager = getWindowManagerService();
// 标注5️⃣
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
});
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowSession;
}
}
@UnsupportedAppUsage
public static IWindowManager getWindowManagerService() {
synchronized (WindowManagerGlobal.class) {
if (sWindowManagerService == null) {
// 标注4️⃣
sWindowManagerService = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
...
}
return sWindowManagerService;
}
}
}
----------------------------------------------------------------------
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
@Override
public IWindowSession openSession(IWindowSessionCallback callback) {
// 标注6️⃣
return new Session(this, callback);
}
public int addWindow(Session session, IWindow client, int seq,
LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState) {
...
// 标注8️⃣
final boolean openInputChannels = (outInputChannel != null
&& (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
if (openInputChannels) {
win.openInputChannel(outInputChannel);
}
...
}
}
----------------------------------------------------------------------
class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
final WindowManagerService mService;
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
Rect outStableInsets, Rect outOutsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState) {
// 标注7️⃣
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel,
outInsetsState);
}
}
标注1️⃣:这里可以看到调用代理类IWindowSession 的addToDisplay()方法,其实调用的是Session类的addToDisplay()方法(后面讲到);
标注2️⃣:通过WindowManagerGlobal的getWindowSession()方法去获取IWindowSession 对象;
标注3️⃣:调用WindowManagerGlobal的getWindowManagerService()方法;
标注4️⃣:这里可以看到获取代理类IWindowManager,通过Bundler IPC,获取到的是WindowManagerService(简称:WMS);
标注5️⃣:调用WindowManagerService的openSession方法();
标注6️⃣:创建Session对象,结合1️⃣,可以知道调用的是Session类的addToDisplay()方法;
标注7️⃣:此时水落石出了,addToDisplay()方法调用到WindowManagerService 的addWindow()
标注8️⃣:在WMS中的addWindow()中会调用WindowState的openInputChannel,把mInputChannel带进入,最终会调用InputManagerService 的registerInputChannel方法注册通道;
四、应用层级的事件分发流程
此时WMS和应用层窗口了已经有了通信的条件。输入事件可以从底层硬件分发到应用层窗口了。最终通过WindowInputEventReceiver这个时间输入处理接受者
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
WindowInputEventReceiver mInputEventReceiver;
...
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
...
// 标注1️⃣
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
...
}
final class WindowInputEventReceiver extends InputEventReceiver {
public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
}
@Override
public void onInputEvent(InputEvent event) {
....
if (processedEvents != null) {
if (processedEvents.isEmpty()) {
// InputEvent consumed by mInputCompatProcessor
finishInputEvent(event, true);
} else {
for (int i = 0; i < processedEvents.size(); i++) {
// 标注2️⃣
enqueueInputEvent(
processedEvents.get(i), this,
QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY, true);
}
}
} else {
// 标注2️⃣
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) {
// 标注3️⃣
doProcessInputEvents();
} else {
// 标注4️⃣
scheduleProcessInputEvents();
}
}
}
标注1️⃣: 创建事件输入处理接收者
标注2️⃣:将事件加入队列
标注3️⃣:处理输入事件
标注4️⃣:最终会通过Handler调用到标注3️⃣的方法
五、事件接收处理流程
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
...
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
...
// 标注1️⃣
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
...
// 标注2️⃣
// Set up the input pipeline.
CharSequence counterSuffix = attrs.getTitle();
mSyntheticInputStage = new SyntheticInputStage();
InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
"aq:native-post-ime:" + counterSuffix);
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;
mFirstPostImeInputStage = earlyPostImeStage;
mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
}
final class ViewPostImeInputStage extends InputStage {
...
private int processPointerEvent(QueuedInputEvent q) {
...
// 标注3️⃣
boolean handled = mView.dispatchPointerEvent(event);
...
}
...
}
}
标注1️⃣: 上述所讲的创建事件输入处理接收者
标注2️⃣:创建输入链;使用的是责任链设计模式;对于不同的输入事件需要使用相应的处理方法,而这些处理方法需要有优先级,所以通过责任链模式,把不同的处理阶段通过一条链串起来是一个很优雅的设计实现。
标注3️⃣:文章头部讲过mView就是DecorView,所以最终会调用到DecorView的dispatchPointerEvent()方法,因为DecorView、FrameLayout 、ViewGroup 都没有重写dispatchPointerEvent()方法,所以最终执行的是View的dispatchPointerEvent()方法,让最顶层父类的事件开始分发。
DecorView层级关系为:DecorView → FrameLayout → ViewGroup → View
六、事件分发处理
@UiThread
public class View implements Drawable.Callback, KeyEvent.Callback,
AccessibilityEventSource {
@UnsupportedAppUsage
public final boolean dispatchPointerEvent(MotionEvent event) {
if (event.isTouchEvent()) {
// 标注1️⃣
return dispatchTouchEvent(event);
} else {
return dispatchGenericMotionEvent(event);
}
}
}
--------------------------------------------------------------------------
public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
private PhoneWindow mWindow;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// 标注2️⃣
final Window.Callback cb = mWindow.getCallback();
return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
// 标注6️⃣
? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}
}
--------------------------------------------------------------------------
public abstract class Window {
private Callback mCallback;
public void setCallback(Callback callback) {
mCallback = callback;
}
// 标注3️⃣
public final Callback getCallback() {
return mCallback;
}
}
--------------------------------------------------------------------------
public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
--------------------------------------------------------------------------
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback, WindowControllerCallback,
AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {
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, IBinder assistToken) {
// 标注4️⃣
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
// 标注5️⃣
mWindow.setCallback(this);
}
// 标注7️⃣
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
}
标注1️⃣:我们知道DecorView的最最最上级是View,在View 的dispatchPointerEvent()方法中,调用了dispatchTouchEvent()方法,又因为DecorView重写了该方法,所以调用的是DecorView的dispatchTouchEvent()方法;
标注2️⃣:获取PhoneWindow 的callback对象,因为Activity实现了 Window.Callback,所以这里实际上获取的实际上是Activity
标注3️⃣:调用getCallback()方法获取mCallback,PhoneWindow 的父类是Window ;
标注4️⃣:创建PhoneWindow对象
标注5️⃣:调用PhoneWindow的setCallback()方法传入当前Activity的this;
标注6️⃣:调用cb.dispatchTouchEvent(ev),经过分析可知调用的是Activity的dispatchTouchEvent()方法;
标注7️⃣:**最终:**调用Activity中的dispatchTouchEvent()方法,我们平时了解最多的是从这里开始。
七、Activity的事件分发(流程①)
public class Activity{
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
// 标记1️⃣
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
public boolean onTouchEvent(MotionEvent event) {
// 标记4️⃣
if (mWindow.shouldCloseOnTouch(this, event)) {
finish();
return true;
}
return false;
}
}
--------------------------------------------------------------------
public class Window{
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public boolean shouldCloseOnTouch(Context context, MotionEvent event) {
// 标记5️⃣
final boolean isOutside =
event.getAction() == MotionEvent.ACTION_UP && isOutOfBounds(context, event)
|| event.getAction() == MotionEvent.ACTION_OUTSIDE;
if (mCloseOnTouchOutside && peekDecorView() != null && isOutside) {
return true;
}
return false;
}
}
*************************************************
public class PhoneWindow extends Window{
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
// 标记2️⃣
return mDecor.superDispatchTouchEvent(event);
}
}
--------------------------------------------------------------------
public class DecorView extends FrameLayout {
public boolean superDispatchTouchEvent(MotionEvent event) {
// 标记3️⃣
return super.dispatchTouchEvent(event);
}
}
👀关注公众号:Android老皮!!!欢迎大家来找我探讨交流👀