该库已经开源到github,地址github.com/AlexMahao/S…java
一个用于监听android事件分发流程的库,两行代码便可在运行时期监听事件的分发流程。android
在编写一些复杂的布局时,经常因为事件分发究竟是哪一个view
处理产生困扰,作法一般须要通过如下步骤:git
View
,重写disaptchTouchEvent
等方法。log
日志。View
.... 若是没有发现问题,无线循环...View
,还原布局文件。对于如上的流程,须要屡次的修改代码,编译等,并且还有还原错误的风险。github
那么有没有一种方式,可以在尽量的少编写代码而实现上述流程,减小对于事件分发打印的困扰呢。json
SimpleTouch
为了解决如上问题而诞生,该库能够在运行时期打印完整的事件分发流程。bash
View
的dispatchTouchEvent
,onTouchEvent
,onInterceptTouchEvent
。json
的形式写入文件。move
事件会自动过滤。no-op
版本,使用时可区分debug
和release
。对于一次完整的手指点击,控制台打印日志以下:app
json
的格式写入到磁盘,便于细致分析。 (因为暂时没找到合适的流程图软件,暂时以json代替)
该展现效果来源于bejson
的视图展现功能。ide
添加依赖布局
在项目的app
下的build.gradle
中添加依赖gradle
debugApi 'com.spearbothy:simple-touch:1.0.5'
releaseApi 'com.spearbothy:simple-touch-no-op:1.0.5'
复制代码
初始化
在项目的Application
的onCreate()
中调用初始化方法Touch.inject(this);
Touch.init(this, new Config().setSimple(false));
复制代码
Config
对象提供一些配置选项
public class Config {
// 输出的日志以极简模式输出
private boolean isSimple = true;
// 是否延迟打印日志,延迟打印日志会在触摸事件结束以后打印,而且具备去重功能
private boolean isDelay = true;
// 是否保留重复的,默认不保留
private boolean isRepeat = false;
// 是否写入到文件
private boolean isPrint2File = true;
// 是否处理,不处理则不会监放任何方法,任何功能都没法生效
private boolean isProcess = true;
}
复制代码
注入代理类(用于监听事件分发)
在Activity
的onCreate()
的super.onCreate(savedInstanceState);
以前调用.
@Override
protected void onCreate(Bundle savedInstanceState) {
Touch.inject(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRootView = (LinearLayout) findViewById(R.id.root);
}
复制代码
使用
编译完成以后,打开app,开始触摸吧!!! 每一次手指离开到触摸请间隔大于1s,目的是对于每次触摸加以区分,暂时没想到合适的判断条件。
备注
no-op
版本,该版本中包含有初始化和注入方法的空实现,以达到debug
和release
使用不一样的版本,使release
不包含任何注入和初始化逻辑。对于该库,其实核心就是怎么可以监听onTouchEvent()
等事件分发方法。
从实现的角度,核心问题在于两个:
view
中事件的hook
。View
替换为生成的代理类对象。生成代理类有如下几种方式:
view
的代理类,而对于自定义view
,能够在编译期经过Processor
生成。java
的动态代理机制。view
对象的时候,替换为构造代理类。根据以上的两种方式,最终所有选择动态的方式,及运行时期动态的生成代理类以及动态的替换view
对象。
java
自己提供了动态代理的机制,可是因为动态代理的对象必须是接口的方法,而view
的事件分发方法都不是某一个接口的方法,那么java
自己的动态代理机制是不行的。
cglib
是java
的一个动态代理库,能够代理类方法。可是由于android中是以dex
方式存储代码,因此没法应用于android
。
dexmaker
是应用于android
的动态生成代码的库。能够用该库实现动态生成代理类。
动态生成代理类的关键点在于ViewProxyBuilder
类,经过该类能够生成代理类对象。
生成的方式以下:
private static View proxy(final View view, AttributeSet attrs) {
try {
return ViewProxyBuilder.forClass(view.getClass())
.handler(new TouchHandler())
.dexCache(view.getContext().getDir(Constants.DEX_CACHE_DIR, Context.MODE_PRIVATE))
.constructorArgTypes(Context.class, AttributeSet.class)
.constructorArgValues(view.getContext(), attrs)
.addProxyMethod(Arrays.asList(Constants.PROXY_METHODS))
.build();
} catch (IOException e) {
return null;
}
}
复制代码
其中handler
为代理方法处理类。
public class TouchHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
TouchMessageManager.getInstance().printBefore(proxy, method, args);
Object result = ViewProxyBuilder.callSuper(proxy, method, args);
TouchMessageManager.getInstance().printAfter(proxy, method, args ,result);
return result;
}
}
复制代码
该类实际上只是在方法前和方法后都打印日志
集成生成了代理对象,还有一个问题就是如何将生成的代理对象和原view`对象替换。
该思路来源于support-v7
,对于继承AppCompatActivity
的页面,其中的TextView
等运行时期都会被替换为AppCompatTextView
。核心即是LayoutInfalter
类,该类用于生成全部的布局对象,同时该类提供生成布局对象的hook
方法,能够添加一下自定义操做。
核心就是调用LayoutInflater.setFactory()
,关键代码以下:
public static void inject(Context context) {
if (sConfig == null || !sConfig.isProcess()) {
return;
}
LayoutInflater inflater;
if (context instanceof Activity) {
inflater = ((Activity) context).getLayoutInflater();
} else {
inflater = LayoutInflater.from(context);
}
ViewFactory factory = new ViewFactory();
if (context instanceof AppCompatActivity) {
final AppCompatDelegate delegate = ((AppCompatActivity) context).getDelegate();
factory.setInterceptFactory(new LayoutInflater.Factory2() {
@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
return delegate.createView(null, name, context, attrs);
}
@Override
public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
return delegate.createView(parent, name, context, attrs);
}
});
}
// 设置hook
inflater.setFactory2(factory);
}
复制代码
com.android.support:appcompat-v7
com.google.dexmaker:dexmaker
com.alibaba:fastjson
com.noober.background:core
有任何疑问能够经过issue
或者以邮件的形式发送到zziamahao@163.com