I wypracowane rozwiązanie z pomocą Rohan :)
I dostosowany jego odpowiedź, aby dopasować moje wymagania.
Gdy użytkownik naciśnie przycisk, rozpoczyna się wątek. Wątek przesypia moje pożądane opóźnienie, a kiedy się budzi, wykonuje kod, który jest mu potrzebny. Kiedy użytkownik puści, wątek zostanie zabity. Osiąga to, co chcę, ponieważ jeśli użytkownik puści, zanim wątek się obudzi, wątek zostanie przerwany, a akcja nie zostanie wykonana.
Podoba mi się to podejście, ponieważ pozwala mi wykonywać swoją logikę biznesową, gdy tylko opóźnienie się skończy, co jest dobre, ponieważ mogę dać użytkownikowi pewne informacje zwrotne, dając do zrozumienia, że pchają wystarczająco długo (telefon może wibrować, na przykład).
Wadą tego podejścia jest: istnieje ryzyko, że użytkownik puści przycisk, gdy pożądane działanie zostanie uruchomione, i zabije wątek, zanim wszystko zostanie zrobione. Nie stanowi to wielkiego problemu w mojej sprawie, ponieważ moja logika biznesowa jest bardzo niewielka; po prostu wystrzeliwuje wydarzenie dla jakiejś innej klasy do przetworzenia. Jeśli działanie nie zakończyło się w pełni, możliwe jest, że użytkownik będzie musiał spróbować ponownie.
Kod jest nieco dłuższy, niż by mi się spodobał, ale jeśli jest to typowa funkcja w aplikacji, można ją łatwo ponownie wykorzystać. Oto przykładowy kod:
protected class MyLongClickListener implements View.OnTouchListener {
private Thread longClickSensor;
public boolean onTouch(View view, MotionEvent event) {
// If the user is pressing down and there is no thread, make one and start it
if (event.getAction() == MotionEvent.ACTION_DOWN && longClickSensor == null) {
longClickSensor = new Thread(new MyDelayedAction());
longClickSensor.start();
}
// If the user has let go and there was a thread, stop it and forget about the thread
if (event.getAction() == MotionEvent.ACTION_UP && longClickSensor != null) {
longClickSensor.interrupt();
longClickSensor = null;
}
return false;
}
private class MyDelayedAction implements Runnable {
private final long delayMs = 1200;
public void run() {
try {
Thread.sleep(delayMs); // Sleep for a while
doBusinessLogic(); // If the thread is still around after the sleep, do the work
} catch (InterruptedException e) { return; }
}
private void doBusinessLogic() {
// Make sure this logic is as quick as possible, or delegate it to some other class
// through Broadcasted Intents, because if the user lets go while the work is happenening,
// the thread will be interrupted.
}
}
}
To prawie robi to, czego potrzebuję. Wpisane podejście wykonuje kod tylko wtedy, gdy użytkownik podnosi palec. Chciałbym, aby moja logika biznesowa działała zaraz po opóźnieniu, a nie po tym, jak użytkownik przestanie naciskać. – ampersandre
Dlaczego jest następnie = getSystemTime() skomentowane? Również metoda getSystemTime() nie działa. Czy miałeś na myśli: System.currentTimeMillis() –
Potwierdzono. Zdefiniuj więc jako długą, nie int. Następnie użyj: then = (Long) System.currentTimeMillis(); a kiedy odnajdziemy różnicę, upewnijmy się, że ponownie rzucamy na długi czas, gdy używamy System.currentTimeMillis() zamiast getSystemTime() –