用戶在網絡請求未返回時連續點擊提交按鈕,觸發多次 submitOrder(),產生重複訂單。
public abstract class NoDoubleClickListener implements View.OnClickListener {
public static final int MIN_CLICK_DELAY_TIME = 1000; // 1秒
private long lastClickTime = 0;
@Override
public final void onClick(View v) {
long currentTime = System.currentTimeMillis();
if (currentTime - lastClickTime > MIN_CLICK_DELAY_TIME) {
lastClickTime = currentTime;
onNoDoubleClick(v);
}
}
public abstract void onNoDoubleClick(View v);
}
submitButton.setOnClickListener(new NoDoubleClickListener() {
@Override
public void onNoDoubleClick(View v) {
submitOrder(); // 業務邏輯
}
});
優勢:零侵入業務代碼,僅替換監聽器與回調方法名,邏輯清晰優雅。
// 錯誤示例
public class SampleActivity extends Activity {
private Handler handler = new Handler() { // 匿名內部類持有外部類引用
@Override
public void handleMessage(Message msg) { ... }
};
private Runnable runnable = new Runnable() { // 同理
@Override public void run() { ... }
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler.postDelayed(runnable, 1000 * 60 * 10); // 10分鐘後執行
finish(); // Activity 銷毀,但 MessageQueue 持有 handler/runnable 引用,導致無法 GC
}
}
public class SampleActivity extends Activity {
private static class MyHandler extends Handler {
private final WeakReference activityRef;
public MyHandler(SampleActivity activity) {
activityRef = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
SampleActivity activity = activityRef.get();
if (activity != null) {
// 安全訪問 activity
}
}
}
private static final Runnable sRunnable = new Runnable() { // 靜態匿名類不持有外部引用
@Override public void run() { /* ... */ }
};
private final MyHandler handler = new MyHandler(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler.postDelayed(sRunnable, 1000 * 60 * 10);
finish(); // 此時 Activity 可正常 GC
}
}
static 內部類或獨立類,斷開對外部類的隱式引用。WeakReference 持有,並在使用前檢查 get() != null。postDelayed 的 Runnable 也必須是靜態的,否則同樣洩漏。onDestroy() 中調用 handler.removeCallbacksAndMessages(null) 進一步保障。