該庫已經開源到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