How does Android intercept of click event frequently operated by user

  • 2021-12-13 16:56:56
  • OfStack

Preface to the table of contents Solutions Scenario 1
Scenario 2
Summarize

Preface

In the development of Android interface, frequent operation is a point that needs attention. Frequent operation: Clicking one button frequently, or clicking multiple item at the same time, etc.

Solutions

Scenario 1

Suppose there is a button T in the Activiyt A interface, and clicking T will jump to Activity B.


void handleClick(){
    Intent intent = new Intent(ActivityA.this,ActivityB.class);
    startActivity(intent);
}

However, the user is likely to click twice in succession, so that ActivityB will start two (standard startup mode in B), and if the user wants to return to ActivityA, he needs to click the return button, which is obviously not a particularly good experience. Presumably, many small partners have encountered it. Naturally, the solution is to judge by time, and prohibit operation within a fixed time. However, you can't write the time judgment once in every method. As such


long lastTime = 0;
void handleClick(){
    long currentTime = System.currentTimeMillis();
    if ( currentTime - lastTime < 200){
        return;
    }
    // Specific operation 
    ...
}

This commonly used method naturally abstracts a class.


public class OperateLock {
    private final static long DEFAULT_PERIOD = 200;
    private final long period;
    private long lastOperatorTime = 0;
    public OperateLock() {
        period = DEFAULT_PERIOD;
    }
    public OperateLock(int minimumPeriod) {
        period = minimumPeriod;
    }
    public boolean doing() {
        boolean doing = false;
        long currentTime = System.currentTimeMillis();
        if (currentTime - lastOperatorTime > period) {
            lastOperatorTime = currentTime;
            doing = true;
        }
        return doing;
    }
    public boolean doing(int minimumPeriod) {
        boolean doing = false;
        long currentTime = System.currentTimeMillis();
        if (currentTime - lastOperatorTime > minimumPeriod) {
            lastOperatorTime = currentTime;
            doing = true;
        }
        return doing;
    }
}

As in the above code, you can change it to


private OperateLock operateLock = new OperateLock();
void handleClick(){
    if (!operateLock.doing()) return;
    // Specific operation 
    ...
}

However, the above code in the case of many button, obviously write many operate objects, which is obviously too much, so, let's continue to modify the code


public class ObjectOperateLock {
    private final static long DEFAULT_PERIOD = 200;
    private final long period;
    private long lastOperatorTime = 0;
    private List< WeakReference > operateObjList = new LinkedList<>();
    private HashMap< WeakReference, Long > timeHashMap = new HashMap<>();
    public ObjectOperateLock() {
        period = DEFAULT_PERIOD;
        Object obj = new Object();
    }
    public ObjectOperateLock(int minimumPeriod) {
        period = minimumPeriod;
    }
    public boolean doing(Object obj) {
        doing(obj, period);
    }
    public boolean doing(Object obj, long minimumPeriod) {
        boolean doing = false;
        long lastOperateTime = 0;
        WeakReference wk = null;
        Iterator< WeakReference > iterator = operateObjList.iterator();
        while (iterator.hasNext()) {
            WeakReference w = iterator.next();
            if (w.get() == null) {
                iterator.remove();
                timeHashMap.remove(w);
            } else if (w.get() == obj) {
                wk = w;
            }
        }
        if (wk == null) {
            wk = new WeakReference(obj);
            operateObjList.add(wk);
            timeHashMap.put(wk, 0L);
            doing = true;
        } else {
            long cur = System.currentTimeMillis();
            lastOperateTime = timeHashMap.get(wk);
            if (cur - lastOperateTime > minimumPeriod) {
                doing = true;
                lastOperateTime = cur;
                timeHashMap.put(wk, lastOperateTime);
            }
        }
        return doing;
    }
}

The code for blocking frequent clicks is changed to:


private ObjectOperateLock operateLock = new ObjectOperateLock();
void handleClickButton1(View v){
    if (!operateLock.doing(v)) return;
    // Specific operation 
    ...
}
void handleClickButton2(View v){
    if (!operateLock.doing(v)) return;
    // Specific operation 
    ...
}

Of course, all methods in ObjectOperateLock can also be changed to static, but that is not conducive to setting a default period. For example, some button may only be clicked once within 200 milliseconds, but other View can only be clicked once within 500 milliseconds. So since you use ObjectOperateLock, you don't need OperateLock. Of course, OperateLock is also useful.

Scenario 2

There is an RecyclerView, which has a pile of item. After item clicks, it will jump into a page. The data carried by item is different, so how to intercept the frequent clicks of item?

Compared with scenario 1, there will be one problem in this scenario, that is, there will be two item clicked at the same time. (Two fingers click on different item at the same time). In this case, you can use OperateLock.


private OperateLock operateLock = new OperateLock();
void handleItemClick(View v){
    if (!operateLock.doing()) return;
}

Summarize

Not only the click button event, but also other frequent operations need to set a specified time for non-repeatable operations, so when encountering these frequent interception operations, write an interception class as needed.


Related articles: