Throw out problem

“Brother, I have a question for you!”

“Ah, say (inner play: how come again… No good! “

“I have a query button on one of my pages that sends out a web request and waits for the results to come back and update the data.”

“Isn’t that good? What’s the problem?”

“Yes, I also feel no problem, but the test is not according to the routine card, the network there is not very good test, she clicked the button because the network is slow, quickly clicked a few more, and then…”

“And then what? ANR?”

“How do you know brother?”

“Here, look at it for you!”

You’ve certainly encountered this in your daily development, so let’s take a look at how to solve this problem.

The first: popover wait

“Boy, come here, look at this, you can do this, when you click the button it will pop up a dialog box, set it to do not close, wait for the network request to complete and then close the dialog box.”

“That’s one way, but how do I write it?”

“Hey, let me give you an example: just write the following code.”

    public void btnDialog(View view) {
        ProgressDialog progressDialog = new ProgressDialog(this);
        progressDialog.setTitle("Wait");
        progressDialog.setMessage("Wait for content");
        //progressDialog.setCanceledOnTouchOutside(false);
        progressDialog.show();
    }
Copy the code

The code above is very simple, but it’s just a way of thinking that clicking on a button will pop up a dialog box that will not allow the user to perform any action (the commented line of code prevents the user from clicking), and then close the dialog box when the request is complete.

This is not recommended, nor is it officially recommended, and the ProgressBar is officially recommended.

Second: prohibit click

“Big brother, I think the pop-up dialog box is not very good, will make users very disgusted, there is another way?”

“Well, I was ready to tell you. There’s more than one! This way, it’s much easier, you just need to set whether the button is clickable or not, and when the user clicks it, it’s not clickable, and then it’s clickable after the request is completed, so I don’t need to write any code for that, right? “

“Hey hey, this need not, you just said there are several kinds, say to hear ah! “

The third kind: time judgment

This is a little more complicated than the above, but it’s still simple.

The specific operation is to define two variables, one is the last click time, one is the time between the click.

// Last click time
private long lastClickTime = 0L;
// Time between clicks (milliseconds)
private static final int FAST_CLICK_DELAY_TIME = 1500;
Copy the code

To judge when clicked, take a look at the code:

public void btnInter(View view) {
  if(System.currentTimeMillis() - lastClickTime >= FAST_CLICK_DELAY_TIME) lastClickTime = System.currentTimeMillis(); }}Copy the code

“Eldest brother, this kind of method looks more easy to use than above two kinds, just need so define once line, I use this kind of ah!”

“Don’t get too excited yet!”

The fourth kind: AOP implementation

“Eldest brother, you just say I happy too early is why ah? “

“This is fine if you only have one page, but what if you have multiple pages with the need to prevent button clicks from being repeated? Define every page, okay? “

“Uh, uh, you’re right, big brother. What should we do? “

“Do you know AOP? And I’m going to talk about it.”

“AOP? What the hell is that? I know OOP! “

“Nice, kid. You know OOP. OOP is object oriented, and AOP is process oriented. “

AOP is an abbreviation of Aspect OrientedProgramming, meaning section-oriented programming. In fact, the so-called aspect oriented programming is a further extraction of business logic, which extracts the common parts of a variety of business logic into a service (such as logging, performance statistics, etc.), so as to achieve code reuse. In addition, this kind of service can dynamically add unified control to the program through configuration. Using AOP, each part of the business logic can be separated, thus reducing the degree of coupling between each part of the business logic.

AOP is not the product of Android, but in Java, Android does not officially provide, so want to use AOP first to import can implement AOP tripartite library:

Add the following code to your project level build.gradle:

The classpath 'com. Hujiang. Aspectjx: gradle - android plugin - aspectjx: 2.0.4'Copy the code

Add a dependency to build. Gradle in moudle:

Implementation 'org. Aspectj: aspectjrt: 1.8.14'Copy the code

You also need to add the following code at the top of moudle’s build.gradle:

apply plugin: 'android-aspectjx'
Copy the code

Click sync Now to update when you’re done.

Since we want to use it everywhere, we define an annotation:

/** * to prevent the button from continuously clicking *@author jiang zhu on 2020/4/19
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SingleClick {
    /* Click the interval */
    long value(a) default 1500;
}
Copy the code

You’ve probably all used this annotation before, except at runtime, but using a scope defines a method that has a parameter called interval time, which is similar in meaning to the third scenario.

You then need to define a class that implements AOP’s specific operations:

@Aspect
public class SingleClickAspect {}
Copy the code

Then define the pointcut and mark the pointcut for all methods that are SingleClick:

    @Pointcut("execution(@com.zj.singclick.SingleClick * *(..) )")
    public void methodAnnotated(a) {}Copy the code

The package name and class name must be written correctly.

Next define an aspect method that wraps around the pointcut method:

    @Around("methodAnnotated()")
    public void aroundJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable {
        View view = null;
        for (Object arg : joinPoint.getArgs()) {
            if (arg instanceof View) {
                view = (View) arg;
                break; }}if (view == null) {
            return;
        }

        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        if(! method.isAnnotationPresent(SingleClick.class)) {return;
        }
        SingleClick singleClick = method.getAnnotation(SingleClick.class);

        if (!isFastDoubleClick(view, singleClick.value())) {

            joinPoint.proceed();
        }
    }
Copy the code

To simple analysis, first look at the annotation in the definition of the pointcut method, and then extract the method parameters, and then extract the annotation of the method, and then call

The isFastDoubleClick method determines whether it is a quick click event, does nothing if it is not, and executes the original method if it is not.

IsFastDoubleClick:

    private static long mLastClickTime;
    private static int mLastClickViewId;

    private static boolean isFastDoubleClick(View v, long intervalMillis) {
        int viewId = v.getId();
        long time = System.currentTimeMillis();
        long timeInterval = Math.abs(time - mLastClickTime);
        if (timeInterval < intervalMillis && viewId == mLastClickViewId) {
            return true;
        } else {
            mLastClickTime = time;
            mLastClickViewId = viewId;
            return false; }}Copy the code

The above code uses both the View ID and the interval time, even though multiple buttons on a page can be distinguished.

“Eldest brother, stop stop stop, all say meng to me, this finish this how to use!”

“Don’t worry, here’s how to use it!”

It is very simple to use, just need to add our custom annotation on the click time method, also can set the interval, if not the default value, also write above, the default value is 1500 milliseconds.

    @SingleClick(2000)
    public void btnAop(View view) {
        ToastUtils.showShort("btnAop");
        Log.e(TAG, "btnAop");
    }
Copy the code

“Isn’t that easy?”

“Big brother, I don’t want to write a lot, I just want to use, can you encapsulate into a library? I use the time direct call line!”

“Hey, okay, I’ll encapsulate it…”

Fourth type of encapsulation

“I’ve packaged the fourth method as a library and uploaded it to the JitPack library. Here’s how to use it!”

Add dependencies to build. Gradle in buildscript. Add dependencies to build.

 dependencies {
        ...
        classpath 'com. Hujiang. Aspectjx: gradle - android plugin - aspectjx: 2.0.4'
 }
Copy the code

Add allProjects repositories in the project’s Build. gradle directory.

allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io'}}}Copy the code

3. Add it at the top of your app’s build.gradle

apply plugin: 'android-aspectjx'
Copy the code

Add dependencies to build. Gradle in the app

implementation 'com. Making. Zhujiang521: AndroidAOP: 1.0.1'
Copy the code

5. Add a comment to the method you want to use:

    @SingleClick(2000)
    public void btnAop(View view) {
        ToastUtils.showShort("btnAop");
        Log.e(TAG, "btnAop");
    }
Copy the code

“Can you use it, boy?”

“By the way, I used Kotlin in my project. I saw that all you wrote were Java. I could use it there.”

“Shout, also Kotlin, rest assured, the same use!”

		@SingleClick
    override fun onClick(v: View?). {
        if(v ! =null) {
            when(v.id){
                R.id.btnClick ->{
                    ToastUtils.showShort("Ha ha ha.")
                    Log.e("Ha ha ha."."wwww")}}}}Copy the code

conclusion

“Is this all right?”

“Ok big brother, hey hey, thank big brother 🙏”

“Go change the project, boy!”

The above scene simulation of some embarrassing 😅, ha ha ha, we can also call directly. If the article is helpful to you, welcome to like attention, if the content of the article is wrong, welcome to point out, very grateful.

Finally, put the project address: [github.com/zhujiang521…] (