「Android 事件分发机制」

「Android 事件分发机制」
一、事件分发机制

Android体系中,事件分发机制占有重要的一份,了解事件的分发机制,对于滑动等冲突才有更深刻的理解。自定义View中能更好的扩展,遇到相关问题能从整个流程上思考,寻找最优解决办法。

  • 一个简单的点击事件是怎样一步步被消费处理的呢?谁该处理,谁不该处理又是由什么因素决定的,这是在实际开发中绕不开的问题,尤其是在自定义View的应用场景下。

  • 先上图,从整体上大致了解事件是怎样被传递与消费的:

view事件分发.png

二、从Activity开始

分析一个最简单的初始页面,Activity布局中仅仅包含一个ViewGroup,首先需要了解View的层级结构。如果此时点击ViewGroup,来看看事件是如何传递的。先来搞清楚Activity的层级结构,基于最新的AppCompatActivity的加载流程,看一下代码实现:

  • CustomActivitysetContentView()
@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,包括是否是包含actionBarfloating等,也即是相当于之前的DecorViewtitleBar

2.等到subDecorView创建流程走完,此时view的层级已经是Activity->PhoneWindow->DecorView->subDecorView了。

activity层级.png

3.当**ensureSubDecor()**执行完毕:

ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
contentParent.removeAllViews();
LayoutInflater.from(mContext).inflate(resId, contentP
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值