android opóźniony keylistener

0

Witam, mam napisany keyListener do klawiatury, po naciśnieciu przycisku jest wysyłany po sokecie jego kod, gdy przycisk naciskam kilka razy zauważyłem że nie zawsze kod jest wysyłany lub jest wysyłany z opóźnieniem, przykładowo nacisnę dwa razy i mam odpowiedź w logcat że nacisnąłem raz, gdy nacisnę trzeci raz to mam dwa wpisy o kliknięciu drugi raz i trzeci. Czy to jest jakiś problem z androidowym buforem ?

0

Twoja obsługa zdarzenia jest prawdopodobnie tak bardzo czasochłonna, że kiedy szybko naciskasz, a więc szybko po sobie generujesz kolejne zdarzenia, to ich obsługa musiałaby się zacząć zanim skończy się obsługa poprzedniego naciśnięcia, puszczenia itp. Generalnie obsługa zdarzeń jest współcześnie implementowana jako jednowątkowa z powodów, które można opisać małą książką. Inaczej mówiąc zanim zacznie się obsługa kolejnego zdarzenia muszą zostać obsłużone wszystkie wygenerowane wcześniej. Nie zawsze jest to możliwe, więc większość GUI jest na to przygotowana i w razie takiej sytuacji następuje zwijanie zdarzeń, czyli łączenie ich ze sobą tam gdzie się da lub po prostu eliminowanie ich z kolejki.
Nie wiem czy wiesz, ale przydział pamięci na stercie jest mniej więcej 10-100 razy wolniejszy niż wykonywanie innych rozkazów, a operacja plikowa jest jeszcze 10-100 razy wolniejszy od przydziału pamięci na stercie. Dlatego w obsłudze zdarzeń generalnie nie powinno używać się żadnych operacji new, ani tym bardziej żadnych operacji plikowych. Jeżeli będzie to potrzebne, to w procedurze obsługi zdarzenia należy zlecić takie długotrwałe zadanie jako zadanie wykonywane w innym wątku.
Ale to nie wszystko. Na początku każdej obsługi zdarzenia z tego samego źródła (takiego jak klawisze) powinieneś sprawdzać flagę obsługi zdarzenia i jeżeli nie jest ustawiona to ją ustawić bo właśnie zaczynasz obsługę zdarzenia. Jeżeli przy wejściu do obsługi zdarzenia będzie ona ustawiona, to natychmiastowo skonsumować je i wyjść z obsługi. Chodzi o to, że zaraz po ustawieniu flagi należy na czas obsługi zdarzeń zdezaktywować ich źródło, czyli na przykład na kontrolce, która generuje zdarzenie ustawić setEnabled(false). W ten sposób jeżeli system z niezależnych od Ciebie powodów przytnie się to użytkownik nie będzie w stanie wygenerować kolejnych zdarzeń i jeszcze zobaczy, że przycisk (jeżeli akurat to on będzie źródłem) stanie się wyszarzony. Jednak między momentem wygenerowania zdarzenia w GUI, a przejściem sterowania do początku Twojej procedury obsługi (a w szczególności wyłączeniem źródła zdarzeń) wykonuje się sporo instrukcji na co idzie trochę czasu. Stąd na jej początku potrzebna jest flaga, żeby wyeliminować kolejne zdarzenia wygenerowane między wystrzeleniem zdarzenia, a dotarciem sterowania do wyłącznika źródła tych zdarzeń. Oczywiście pod koniec obsługi należy z powrotem włączyć źródło zdarzeń takie jak przycisk oraz wyłączyć flagę obsługi zdarzenia.
Krótko mówiąc - część zbyt szybko następujących zdarzeń jest eliminowana przez system operacyjny i/lub wątek obsługi zdarzeń Javy, ale przyczyna problemu leży po Twojej stronie. Powinieneś mieć szybszą/krótszą procedurę obsługi zdarzenia.

Co jest szybkie?

  1. ustawianie flag (x1), przypisywanie zmiennych, w tym operacje na referencjach do obiektów (x1)
  2. proste obliczenia stało i zmiennoprzecinkowe (x1)
  3. utworzenie i wystartowanie nowego wątku (x2)
  4. synchronizacja wielowątkowa (x5)

Co jest czasochłonne?

  1. sleep (x100..∞)
  2. tworzenie obiektów na stercie (x10)
  3. tworzenie, odczyt, zapis plików (x100..x1000)
  4. otwieranie połączeń sieciowych i transmisja. (x10..x10000)
  5. interaktywna obsługa błędów (x1000000..∞)

Teraz mniej więcej wiesz dlaczego nie łapiesz wszystkich zdarzeń. W nawiasach podałem skalę opóźnień w stosunku do najszybszych operacji, żebyś mógł sobie to wyobrazić.

ps. Dla opornych: Wyświetlanie na ekranie lub zapisywanie do loga jest operacją plikową. :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1