Prevent multiple clicks on Android

2

I have a user registration screen where I avoid the possibility of multiple clicks to the button to register through the method View.setEnabled () . I proceed as follows: in the method onClick () , from the View.OnClickListener interface, disable the button, and after the request has ended, the onPostExecute () AsyncTask re-enables it.

Although it's a simple solution, I read in the American SO that this solution does not adequately resolve the problem. In the response given in this thread the author cites the fact that the clicks are queued up for execution later.

In the face of this fact I ask: is the solution adopted in the US OS the final solution to solve the problem or is there a better or ideal solution to solve it?

    
asked by anonymous 13.05.2015 / 21:03

1 answer

1

Yes, this problem occurs because it postpones click detection using post and postDelayed , and this will queue the ACTION_UP events. This can be seen by the source code of the View class:

// Use a Runnable and post this rather than calling
// performClick directly. This lets other visual state
// of the view update before click actions start.
if (mPerformClick == null) {
    mPerformClick = new PerformClick();
}

if (!post(mPerformClick)) {
    performClick();
}

I can not think of a better way to do it, the flag is enough.

But I think you can improve this a bit by making this logic centered on a subclass of Button . This way you avoid code replication, and make it transparent to anyone who uses it. It would still be necessary to set setEnabled because of asynchronous processing, otherwise just make the management of the enabled flag before and after the performClick call of the parent ( super ).

My suggestion would be:

public class SingleClickButton extends Button {
    public SingleClickButton(Context context) {
        super(context);
    }

    public SingleClickButton(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public SingleClickButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public SingleClickButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public boolean performClick() {
        return isEnabled() && super.performClick();
    }
}

This solution will still queue events, but will not let it run over and over again. To avoid the accumulation of events, there would have to be onTouchEvent overwriting, but it is a more aggressive approach and I think it is unnecessary.

To use in your layout, simply declare the tag with the entire path of the package and class:

<nome.do.seu.pacote.SingleClickButton
    ...
/>
    
14.05.2015 / 03:47