Kontrolka wyszukiwania zdjęć
Aby przetestować nasze GUI dodamy do niego jeszcze jeden element - wyszukiwarkę. Jako mechanizmu wyszukiwania użyjemy kodu znanego z poprzednich zajęć.
-
W pliku FXML do górnego HBoxa dodaj dwie kontrolki - pole tekstowe oraz przycisk wyszukiwania:
<TextField fx:id="searchTextField" promptText="Enter search query..." prefWidth="580"/> <Button text="Search" /> -
W kodzie kontrolera podepnij kontrolkę searchTextField, a następnie dodaj pustą metodę, która będzie wywoływana w reakcji na kliknięcie w przycisk:
public void searchButtonClicked(ActionEvent event) { } -
W widoku FXML powiąż przycisk z metodą dodając do niego atrybut
onAction="#searchButtonClicked". -
Uruchom program, gotowe okienko powinno wyglądać tak jak poniżej:

Obsługa asynchronicznego wyszukiwania
-
W przygotowanej metodzie
searchButtonClicked()stwórz instancję PhotoDownloader. -
Przygotuj obsługę wyszukiwania w następujący sposób:
- Wyczyść obecną galerię (
Gallery#clear()). - Wywołaj metodę
PhotoDownloader#searchForPhotos()przekazując do niej zawartość polasearchTextField. - Zasubskrybuj się na otrzymanym
Observablew taki sposób by każde zdjęcie przychodzące ze strumienia było dodawane do modelu galerii (Gallery#addPhoto()).
- Wyczyść obecną galerię (
-
Przetestuj otrzymane rozwiązanie. Zastanów się, dlaczego aplikacja nie jest responsywna w czasie wyszukiwania (po kliknięciu w przycisk
Search). -
Ustaw strumień pobierający zdjęcia tak by wyszukiwanie wykonywało się w osobnym wątku (operator
subscribeOn()). Przetestuj ponownie cały mechanizm. Spojrzyj też w logi aplikacji na konsoli. Czy obserwujesz jakieś niestandardowe wyjątki? Dlaczego? -
Aby zabezpieczyć wykonywanie operacji w UI każda operacja aktualizująca nasłuchiwany model powinna być wykonywana w wątku FX. Służy do tego mechanizm runLater():
Platform.runLater(() -> /* add something to event queue of the UI thread */ );Wykorzystaj powyższy mechanizm by opakować dodawanie zdjęć do modelu galerii otrzymywanych podczas wyszukiwania.
Zamiast używać
Platform.runLater()możesz też skorzystać RX-owego operatoraobserveOn()oraz biblioteki RxJavaFx, która dostarcza m. in. specjalnyScheduler, z którego można korzystać wymiennie z innymi:source.subscribeOn(Schedulers.io()) .observeOn(JavaFxScheduler.platform()) .subscribe(/* do some UI-dependendent modifications here */);
Zauważ, że duży narzut czasowy generuje nie tylko samo wyszukiwanie w internecie, ale także zapisywanie zdjęć na dysk. Po wykonaniu wszystkich zadań przeanalizuj metodę PhotoSerializer#savePhoto. Zastanów się, jaki mechanizm został w niej zastosowany i jak wpływa on na responsywność aplikacji.