On devices running Android 2.2, I want to detect when the user has pressed the screen for a certain length of time. Imagine sending a morse code message, with short taps (dots) and longer presses (dashes). I want to react to short taps as soon as the user lifts her finger, and to longer presses after (say) 500 milliseconds, even if she continues to hold her finger down.
I've looked at both FutureTask and ScheduledExecutorService but these look like overkill for this implementation. Or perhaps I just have cold feet about dealing directly with threads, and seeing all the code that is needed to handle them.
Here's simplified pseudo-code for how I have done this sort of thing in other languages:
public boolean onTouch(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
timer = createObjectToCallback(callbackMethod, 500); // milliseconds
} else if (event.getAction() == MotionEvent.ACTION_UP) {
if (timer still exists) {
timer.kill();
// Do the short press thing
} else {
// Do nothing. It already happened when callbackMethod was triggered
}
}
}
public void callbackMethod() {
// Do the long press thing. The timer has already auto-destructed.
}
What simple ways are there of doing this in Java?
== EDIT in response to the answer from @zapl ==
Writing code that works is one thing. Understanding how it works is another.
If I understand correctly, the thread that updates the UI is already running in a loop. Let's imagine a very simple case.
The Main activity creates a black canvas, and contains an onTouch
method. When it starts, it calls setOnTouchListener
. The Main thread now listens constantly to input from the screen. If the way the user is touching the screen has changed, it calls the onTouch
method, with information about the change.
Let's say that the onTouch
method draws a green circle around the touch point. This circle is drawn using cycles belonging to the Main thread. When the drawing is finished, the Main thread starts checking for new changes from the screen. If there are no changes, then onTouch
is not called again, and the green dot does not move.
When the user lifts her finger, the screen provides changed information to the Main thread, and the code in the onTouch
method erases the dot.
Create interface
Has the screen detected a change? No: loop
Has the screen detected a change? No: loop
...
Has the screen detected a change? Yes: draw a green dot; loop
Has the screen detected a change? No: loop.
...
Has the screen detected a change? Yes: new position => redraw the green dot; loop
...
Has the screen detected a change? Yes: not touching => remove dot; loop
Has the screen detected a change? ...
Suppose that I want the dot to turn red if the user's finger does not move for at least 500 ms. No move means no callback to onTouch
. So I can set up a Handler
, which adds itself to the loop in the Main thread. The Main thread now has two actions in its loop.
Create interface
Has the screen detected a change? No: loop
Has the screen detected a change? No: loop
...
Has the screen detected a change? Yes: a touch; draw a green dot; add Handler; loop
Has the screen detected a change? No;
Is it time for Handler to trigger? No: loop.
...
Has the screen detected a change? No;
Is it time for Handler to trigger? Yes: change dot color to red; remove Handler; loop.
Has the screen detected a change? No: loop.
...
Has the screen detected a change? Yes: not touching => remove dot; loop
Has the screen detected a change? ...
Any code executed by the Handler
will block the Main thread until it has completed.
Is that an accurate description of what Handler
does?