1. Abstract classes

// Implement the view. OnClickListener interface
public abstract class OnThrottleClickListener implements View.OnClickListener {
    private static final String TAG = "OnThrottleClickListener";
    private static final int SKIP_DURATION = 300;//milliseconds
    private long mLastClickTime;
    @Override
    public void onClick(View v) {
        if (System.currentTimeMillis() - mLastClickTime > SKIP_DURATION) {
            onThrottleClick(v);
            mLastClickTime = System.currentTimeMillis();
        } else {
            Log.e(TAG, "OnThrottleClickListener: Repeat click"); }}protected abstract void onThrottleClick(View v);
}
Copy the code
// Instead of new view.onClickListener ()
id_tv_1.setOnClickListener(new OnThrottleClickListener() {
     @Override
     protected void onThrottleClick(View v) {
       Log.e(TAG, "onClick: OnThrottleClickListener "); }});Copy the code

2. Proxy mode

// The proxy class implements the view. OnClickListener interface
public class ThrottleClickProxy implements View.OnClickListener {
    private static final String TAG = "ThrottleClickProxy";
    private static final int SKIP_DURATION = 300;//milliseconds
    private long mLastClickTime;
    / / the source object
    private View.OnClickListener mOriginListener;
	/ / structure
    public ThrottleClickProxy(View.OnClickListener mOriginListener) {
        this.mOriginListener = mOriginListener;
    }
    @Override
    public void onClick(View v) {
        if (System.currentTimeMillis() - mLastClickTime >= SKIP_DURATION) {
            mOriginListener.onClick(v);
            mLastClickTime = System.currentTimeMillis();
        } else {
            Log.e(TAG, "ThrottleClickProxy: Repeat click"); }}}Copy the code
/ / use
id_tv_2.setOnClickListener(new ThrottleClickProxy(new View.OnClickListener() {
          @Override
          public void onClick(View v) {
                Log.e(TAG, "onClick: ThrottleClickProxy "); }}));Copy the code

3, RxBinding for RxAndroid

implementation 'com. Jakewharton. Rxbinding3: rxbinding: 3.0.0-1'
Copy the code
 RxView.clicks(id_tv_3)
       .throttleFirst(300, TimeUnit.MILLISECONDS)
       .subscribe(new Consumer<Unit>() {
          @Override
          public void accept(Unit unit) throws Exception {
              Log.e(TAG, "onClick: throttleFirst "); }});Copy the code

Eclipse AspectJ for AOP

// Use AspectJX to quickly configure Eclipse AspectJ
//project
dependencies {
        classpath "Com. Android. Tools. Build: gradle: 4.1.2." "
        //add
        classpath 'com. Hujiang. Aspectjx: gradle - android plugin - aspectjx: 2.0.10'
}
Copy the code
plugins {
    id 'com.android.application'
    //add
    id 'android-aspectjx'
}
//application module
dependencies {
    //add
    implementation 'org. Aspectj: aspectjrt: 1.9.5'
}
Copy the code
@Aspect
public class ThrottleClickAspect {
    private static final String TAG = "ThrottleClickAspect";
    private static final int SKIP_DURATION = 3000;
    private long mLastClickTime;

    . / / all android view. The view. An OnClickListener. OnClick method will be woven into, as the third party components RxView. On () will be, too
    @Around("execution(* android.view.View.OnClickListener.onClick(..) )"
    public void aroundViewOnClick(ProceedingJoinPoint joinPoint) throws Throwable {
        if (System.currentTimeMillis() - mLastClickTime >= SKIP_DURATION) {
            joinPoint.proceed();
            mLastClickTime = System.currentTimeMillis();
        } else {
            Log.e(TAG, "ThrottleClickAspect: Repeat click"); }}}Copy the code
  • Code is non-invasive. It’s working

Explicitly specified by annotation

  • Add @throttleclick annotation
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ThrottleClick {
    int skipDuration(a) default 1000;
}
Copy the code
  • Modify ThrottleClickAspect class
@Aspect
public class ThrottleClickAspect {
    private static final String TAG = "ThrottleClickAspect";
    private static final int SKIP_DURATION = 300;
    // private int mLastClickViewId;
    private long mLastClickTime;
    // The declaration is the annotation mark pointcut
	/ / package path
    @Pointcut("execution(@com.louisgeek.aop.ThrottleClick * *(..) )"
    public void pointcutThrottleClick(a) {
        Log.e(TAG, "pointcutThrottleClick: ");
    }
	//
    @Around("pointcutThrottleClick()")
    public void aroundThrottleClick(ProceedingJoinPoint joinPoint) throws Throwable {
        //
        View view = null;
        for (Object arg : joinPoint.getArgs()) {
            if (arg instanceof View) {
                view = (View) arg;
                break; }}if (view == null) {
            return;
        }
        // Retrieve the annotation of the method
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        if(! method.isAnnotationPresent(ThrottleClick.class)) {return;
        }
        ThrottleClick throttleClick = method.getAnnotation(ThrottleClick.class);
        //
        if (throttleClick == null) {
            return;
        }
        int skipDuration = throttleClick.skipDuration();
        if (skipDuration < 0) {
            skipDuration = SKIP_DURATION;
        }
        if (System.currentTimeMillis() - mLastClickTime >= skipDuration) {
            // Continue execution
            joinPoint.proceed();
            mLastClickTime = System.currentTimeMillis();
        } else {
            Log.e(TAG, AroundThrottleClick: Click again); }}}Copy the code
/ / use
id_tv_4.setOnClickListener(new View.OnClickListener() {
           // Annotate the markup
            @ThrottleClick
            @Override
            public void onClick(View v) {
                Log.e(TAG, "onClick: @ThrottleClick "); }});Copy the code