Android中如何優(yōu)雅的處理重復(fù)點擊實例代碼
問題
有時候有些操作是防止用戶在一次響應(yīng)結(jié)束中再響應(yīng)下一個。但有些測試用戶就要猛點,狂點。像這種惡意就要進行防止。
比如在客戶端中,一些按鈕一般是需要避免重復(fù)點擊的,比如:購買丶支付丶確定丶提交丶點贊丶收藏等等場景,這些場景短時間內(nèi)的重復(fù)點擊會引發(fā)一些問題.
下面話不多說了,來一起看看詳細的介紹吧
以前的處理方式
可能是采用手動記錄最后的點擊時間,再通過計算時間間隔來判斷是否重復(fù)點擊
private long mLastClickTime = 0;
public static final int TIME_INTERVAL = 1000;
private Button mButton;
private void initView() {
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (System.currentTimeMillis() - mLastClickTime >= TIME_INTERVAL) {
//to do
mLastClickTime = System.currentTimeMillis();
} else {
Toast.makeText(getActivity(), "請勿重復(fù)點擊", Toast.LENGTH_LONG).show();
}
}
});
}
或者封裝一下采用抽象處理
public abstract class IClickListener implements View.OnClickListener {
private long mLastClickTime = 0;
public static final int TIME_INTERVAL = 1000;
@Override
public final void onClick(View v) {
if (System.currentTimeMillis() - mLastClickTime >= TIME_INTERVAL) {
onIClick(v);
mLastClickTime = System.currentTimeMillis();
} else {
onAgain(v);
}
}
protected abstract void onIClick(View v);
protected void onAgain(View v) {
}
}
使用(無需提醒重復(fù)點擊)
mButton.setOnClickListener(new IClickListener() {
@Override
protected void onIClick(View v) {
}
});
或者(需提醒重復(fù)點擊)
mButton.setOnClickListener(new IClickListener() {
@Override
protected void onIClick(View v) {
}
@Override
protected void onAgain(View v) {
}
});
可以看到經(jīng)過封裝之后,使用起來還是很方便的,但是有幾個缺點
- 侵入性過大-OnClickListener全部替換為子類IClickListener
- 不可逆-不能很方便的還原為OnClickListener,因為不是同個回調(diào)
- 如果是第三方控件則無法處理重復(fù)點擊
- 只能寫成內(nèi)部類方式-由于單繼承特性,我們只能內(nèi)部類回調(diào),代碼不美觀
優(yōu)雅的處理方式
重復(fù)點擊的問題其實是如何動態(tài)控制原有的點擊事件是否產(chǎn)生,而不是在原有的點擊事件上增強功能;結(jié)合設(shè)計模式可以知道,代理模式可以很好的處理這種問題,而不是繼承.
代理
public class ClickProxy implements View.OnClickListener {
private View.OnClickListener origin;
private long lastclick = 0;
private long timems = 1000;
public ClickProxy(View.OnClickListener origin) {
this.origin = origin;
}
@Override
public void onClick(View v) {
if (System.currentTimeMillis() - lastclick >= timems) {
origin.onClick(v);
lastclick = System.currentTimeMillis();
}
}
}
原先的點擊事件
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//to do
}
});
代理使用
mButton.setOnClickListener(new ClickProxy(new View.OnClickListener() {
@Override
public void onClick(View v) {
//to do
}
}));
可以看到,原有代碼邏輯沒有改動,只是添加了代理類,這樣大大減小了侵入性
當(dāng)然還可以擴展一下,提供重復(fù)點擊的回調(diào)和自定義間隔時間,增加一個構(gòu)造函數(shù)
public class ClickProxy implements View.OnClickListener {
private View.OnClickListener origin;
private long lastclick = 0;
private long timems = 1000; //ms
private IAgain mIAgain;
public ClickProxy(View.OnClickListener origin, long timems, IAgain again) {
this.origin = origin;
this.mIAgain = again;
this.timems = timems;
}
public ClickProxy(View.OnClickListener origin) {
this.origin = origin;
}
@Override
public void onClick(View v) {
if (System.currentTimeMillis() - lastclick >= timems) {
origin.onClick(v);
lastclick = System.currentTimeMillis();
} else {
if (mIAgain != null) mIAgain.onAgain();
}
}
public interface IAgain {
void onAgain();//重復(fù)點擊
}
}
如何處理第三方View內(nèi)部的點擊事件
可能我們使用一個自定義控件,他的內(nèi)部已經(jīng)消費了點擊事件,但是需要避免重復(fù)點擊,我們不可能去改內(nèi)部的代碼,也不能重新設(shè)置點擊事件,那樣會丟失內(nèi)部的處理邏輯;這時可以采用反射的處理方式,再結(jié)合代理來實現(xiàn)無縫替換
//提供一個靜態(tài)方法
public class ClickFilter {
public static void setFilter(View view) {
try {
Field field = View.class.getDeclaredField("mListenerInfo");
field.setAccessible(true);
Class listInfoType = field.getType();
Object listinfo = field.get(view);
Field onclickField = listInfoType.getField("mOnClickListener");
View.OnClickListener origin = (View.OnClickListener) onclickField.get(listinfo);
onclickField.set(listinfo, new ClickProxy(origin));
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用:
private StateButton mStateButton;//自定義控件
private void initView() {
ClickFilter.setFilter(mStateButton);
}
這種動態(tài)替換的方式同樣適合普通場景,在設(shè)置點擊事件后,都可以通過設(shè)置該過濾器來處理重復(fù)點擊(包括butterknife等注解綁定的點擊事件)
最后
Ok.以上就是討論如何優(yōu)雅處理重復(fù)點擊的全部內(nèi)容,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
Android貝塞爾曲線初步學(xué)習(xí)第三課 Android實現(xiàn)添加至購物車的運動軌跡
這篇文章主要為大家詳細介紹了Android貝塞爾曲線初步學(xué)習(xí)第三課,Android實現(xiàn)添加至購物車的運動軌跡,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-03-03
Android關(guān)于Button背景或樣式失效問題解決方法
大家好,本篇文章主要講的是Android關(guān)于Button背景或樣式失效問題解決方法,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下2022-01-01
Android 詳解ThreadLocal及InheritableThreadLocal
這篇文章主要介紹了Android 詳解ThreadLocal及InheritableThreadLocal的相關(guān)資料,需要的朋友可以參考下2017-01-01
Android應(yīng)用程序轉(zhuǎn)到后臺并回到前臺判斷方法
這篇文章主要介紹了Android應(yīng)用程序轉(zhuǎn)到后臺并回到前臺判斷方法的相關(guān)資料,需要的朋友可以參考下2016-11-11
Android長按imageview把圖片保存到本地的實例代碼
本文通過代碼給大家介紹了Android長按imageview把圖片保存到本地的實現(xiàn)方法,代碼簡單易懂,非常不錯,具有參考借鑒價值,需要的朋友參考下吧2017-12-12

