簡論
每個APP幾乎都會有個登陸功能,也自然需要某些按鈕點擊後驗證是否登陸,沒有登陸則跳轉登陸界面, 較爲龐大的項目可能每個模塊之間的跳轉都不同,我們傳統的寫法就是實現不同的OnClickListener類,然後將其實例set進去,又或者在BaseActivity中擴展其他方法,功能上是沒問題,不過這樣的寫法讓人有點頭疼, 同界面可能這個需要驗證那個不需要驗證那麼就需要兩套方式來解決,後期改動對於公司新人也不是很友好。所以,可以整個類似攔截器一樣的東西, 在保證原始寫法的同時,使用某些方法,或者註解的形式標註是否需要驗證, 這種效果筆者感覺還是比較理想。
反射
要說到攔截原生點擊事件, 第一個想法就是用到反射了
public void setOnClickListener(@Nullable OnClickListener l) {
if (!isClickable()) {
setClickable(true);
}
getListenerInfo().mOnClickListener = l;
}
View的點擊觸摸等手勢事件都會被存放在一個ListenerInfo對象中,於是我們可以通過反射獲取ListenerInfo對象然後再次反射獲取到OnClickListener,然後重新爲這個View設置一個點擊事件, 這個點擊事件的執行爲先判斷是否登陸,沒有登陸去登陸,否則執行獲取到的OnClickListener,就是這麼簡單
Object info = ReflectUtils.reflect(v).field("mListenerInfo").get();
final View.OnClickListener oriClick = ReflectUtils.reflect(info).field("mOnClickListener").get();
v.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (!loginChunk.verifyLogin()) {
loginChunk.goLogin();
} else if (oriClick != null) {
oriClick.onClick(view);
}
}
});
同樣適用於第三方庫
BaseRecyclerViewAdapterHelper
final BaseQuickAdapter.OnItemClickListener itemClickListener = ReflectUtils.reflect(adapter).field("mOnItemClickListener").get();
if (itemClickListener == null)
return;
adapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
if (!loginChunk.verifyLogin())
loginChunk.goLogin();
else if (itemClickListener != null) {
itemClickListener.onItemClick(adapter, view, position);
}
}
});
性能
反射確實會帶來一些性能上問題, 原本7ms可以打開的界面反射後可能會10ms甚至更久, 但是設定點擊事件與ui的刷新毫無關聯,所以我們完全可以放在子線程中進行。
換種更加簡潔的方式實現,定義一個註解
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginDunk {
}
從一個實例中獲取標註註解的View,
Field[] fields = instance.getClass().getDeclaredFields();
List<View> signViews = new ArrayList<>();
for (Field field : fields) {
if (field.getAnnotation(LoginDunk.class) == null)
continue;
if (field.getType() != View.class)
continue;
field.setAccessible(true);
signViews.add((View) field.get(instance));
}
回去到View後執行之前的步驟即可
GitHub已經爲您做好了封裝非侵入式實現點擊校驗登陸跳轉 如果能助到您,希望留個star,謝謝?