「Android 事件分发机制」
一、事件分发机制
在
Android体系中,事件分发机制占有重要的一份,了解事件的分发机制,对于滑动等冲突才有更深刻的理解。自定义View中能更好的扩展,遇到相关问题能从整个流程上思考,寻找最优解决办法。
-
一个简单的点击事件是怎样一步步被消费处理的呢?谁该处理,谁不该处理又是由什么因素决定的,这是在实际开发中绕不开的问题,尤其是在自定义View的应用场景下。
-
先上图,从整体上大致了解事件是怎样被传递与消费的:

二、从Activity开始
分析一个最简单的初始页面,Activity布局中仅仅包含一个ViewGroup,首先需要了解View的层级结构。如果此时点击ViewGroup,来看看事件是如何传递的。先来搞清楚Activity的层级结构,基于最新的AppCompatActivity的加载流程,看一下代码实现:
- CustomActivity中setContentView()
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView();
}
- AppCompatActivity中
//#1
@Override
public void setContentView(@LayoutRes int layoutResID) {
getDelegate().setContentView(layoutResID);
}
//#2
@NonNull
public AppCompatDelegate getDelegate() {
if (mDelegate == null) {
mDelegate = AppCompatDelegate.create(this, this);
}
return mDelegate;
}
//#3 AppCompatDelegateImpl
@Override
public void setContentView(int resId) {
ensureSubDecor();
ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
contentParent.removeAllViews();
LayoutInflater.from(mContext).inflate(resId, contentParent);
mAppCompatWindowCallback.getWrapped().onContentChanged();
}
1.AppCompatDelegate是个啥?自从切换到AppCompatActivity以后,加载 setContentView() 跟之前的流程有差异。
2.先看一段关于抽象类AppCompatDelegate注释:
This class represents a delegate which you can use to extend AppCompat's support to any Activity.When using an AppCompatDelegate, you should call the following methods instead of the Activity method of the same name...了解到,AppCompatDelegate其实是委托类,而这个类是为了兼容Activity而增加的。几乎支持了所有Activity的操作,且方法同名。
3.AppCompatDelegate作为抽象类,那么具体的实现细节得找到它的实现类,也就是-AppCompatDelegateImpl,那么在setContentView(),它到底做了哪些操作呢?而整个调用流程从 #1-#3,加上我们自己定义的CustomActivity应该是:CoustomActivity#setContentView->AppCompatActivity#setContentView->AppCompatActivity#getDelegate->AppCompatDelegate#setContentView
- AppCompatDelegate的实现类AppCompatDelegateImpl
对setContentView简单分析,看看具体做了哪些操作:
@Override
public void setContentView(int resId) {
ensureSubDecor();
ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
contentParent.removeAllViews();
LayoutInflater.from(mContext).inflate(resId, contentParent);
mAppCompatWindowCallback.getWrapped().onContentChanged();
}
1.ensureSubDecor()
如果熟悉Activity的启动流程的话,应该对Decor并不陌生,似乎有点是DecorView的意思,那到底是不是呢?**ensureSubDecor()**创建出来的是什么?
private void ensureSubDecor() {
if (!mSubDecorInstalled) {
mSubDecor = createSubDecor();
}
//.....
}
private ViewGroup createSubDecor() {
TypedArray a = mContext.obtainStyledAttributes(R.styleable.AppCompatTheme);
//.....
ensureWindow();
mWindow.getDecorView();
final LayoutInflater inflater = LayoutInflater.from(mContext);
ViewGroup subDecor = null;
if (!mWindowNoTitle) {
if (!mWindowNoTitle) {
// If we're floating, inflate the dialog title decor
subDecor = (ViewGroup) inflater.inflate(
R.layout.abc_dialog_title_material, null);
// Floating windows can never have an action bar, reset the flags
mHasActionBar = mOverlayActionBar = false;
} else if (mHasActionBar) {
}
}
mWindow.setContentView(subDecor);
//....
return subDecor;
}
1.通过对createSubDecor创建过程分析,发现它并不是Window中的DecorView,而是在创建DecorView之后创建的一个subDecorView,包括是否是包含actionBar、floating等,也即是相当于之前的DecorView中titleBar。
2.等到subDecorView创建流程走完,此时view的层级已经是Activity->PhoneWindow->DecorView->subDecorView了。

3.当**ensureSubDecor()**执行完毕:
ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content); contentParent.removeAllViews(); LayoutInflater.from(mContext).inflate(resId,

本文深入探讨Android的事件分发机制,从Activity开始,详细分析了事件如何从Activity经PhoneWindow、DecorView到ViewGroup层层传递。文章还介绍了如何自定义一个不可点击的RecyclerView,以及事件分发机制在实际开发中的应用。最后,提到了一系列Android进阶学习资源,如Java基础、框架设计、性能优化、NDK开发等。
最低0.47元/天 解锁文章
422

被折叠的 条评论
为什么被折叠?



