Naučit se PHP Naučit se PHP
Extra 10 % bodů navíc a tričko zdarma při zadání kódu "TRIKO10"

Diskuze: Sítové programování Socket - blokování

Java Java Sítové programování Socket - blokování American English version English version

Aktivity (1)
Avatar
Jiří Hrdina:15.11.2018 16:58

Ahoj,

nemůžu se pořádně dopátrat odpovědi, která by mi podařila pochopit problém.

Jakým způsobem se blokuje Socket a s ním BufferedReader, PrintWriter v sítovém programování?
Co jsem pochopil, tak je dobré mít vlákno na každý zápis/čtení... Mohl bych poprosit o vysvětlení?

Děkuji

 
Odpovědět 15.11.2018 16:58
Avatar
Petr Štechmüller
Překladatel
Avatar
Odpovídá na Jiří Hrdina
Petr Štechmüller:15.11.2018 17:30

Ahoj, třída Socket obsahuje dva data streamy:

  • inputStream - slouží pro čtení dat z "internetu"
  • outputStream - slouží k zápisu dat ven

Čtení je obecně blokující záležitost. Když se podíváš na jakoukoliv implementaci třídy InputStream, tak všechny metody typu read* budou blokující. To znamená, že budou číst až do "konce". Jak je konec definovaný, záleží na konkrétní implementaci.

V síťovém programování je tedy doporučený, aby jsi četl data v samostatném vlákně (tzv. čtecí vlákno) a když přijdou data, tak "nějakým" způsobem informuješ "někoho", aby se o ta data postaral.

To samé platí pro zápis dat do streamu. To je taky blokující záležitost, která může trvat velmi dlouho. Proto se pro zápis vytváří také samostatné vlákno (tzv. zapisovací vlákno), které se pouze stará o odesílání zpráv.

Nahoru Odpovědět 15.11.2018 17:30
Pokud spolu kód a komentář nekorespondují, budou patrně oba chybné
Avatar
Jiří Hrdina:16.11.2018 8:29

Ahoj, děkuji za odpověd. Takže ideální stav je, že budu mít dvě vlákna v klientovi (jedno, co se bude starat o outputstream a jedno o inputStream)? Jakým způsobem zařídit to vlákno, které se bude starat o output? Jak mu dát vědět, že má poslat zprávu? Tak mě napadá nějaká fronta zpráv nebo něco takového?

A je tedy ideální mít: 2 vlákna v klientovi a i 2 vlákna na straně druhé? Třeba budu mít třídu Server, dal bych tam vnitřní třídu privátní, která bude vlákno a bude udržovat informaci o spojení, takže bude mít přes Konstruktor Socket. A tohle vlákno se bude pouštět vždy, když se připojí klient na server. A do této třídy vložím ještě další dvě vlákna - pro čtení a druhé pro zápis? Chápu to správně?

 
Nahoru Odpovědět 16.11.2018 8:29
Avatar
Petr Štechmüller
Překladatel
Avatar
Odpovídá na Jiří Hrdina
Petr Štechmüller:16.11.2018 9:10
  1. Používej tlačítko odpovědět.
  2. Na klientovi opravdu budeš mít dvě vlákna (čtení, zápis)
  3. Pro odesílání zpráv je fronta zpráv ideální
  4. Co se serveru týče, tam je to na zvážení.

Existuje několik variant, jak řešit vlákna na serveru, vše asi nejvíce záleží na předpokládané zátěži.

  1. každému klientovi vytvoř dvě vlákna (čtení, zápis)
  2. trochu lepší řešení je, mít jenom jedno odesílací vlákno na serveru a veškeré zprávy odesílat v tomto vlákně, tím se dost ušetří zdroje

Nedávno jsem tu publikoval články o tvorbě serveru v Javě, tak se na to můžeš podívat, všechno je tam řešený.

Nahoru Odpovědět 16.11.2018 9:10
Pokud spolu kód a komentář nekorespondují, budou patrně oba chybné
Avatar
Odpovídá na Petr Štechmüller
Erik Šťastný:16.11.2018 9:36

V případě aplikace pro větší množství klientů bych rozhodně možnost "a." vynechal. V případě, že by server měl stovky, ne-li tisíce klientů, tak mít pro každého vytvořené dva thready je dost špatné.

 
Nahoru Odpovědět 16.11.2018 9:36
Avatar
Petr Štechmüller
Překladatel
Avatar
Odpovídá na Erik Šťastný
Petr Štechmüller:16.11.2018 9:52

Jasně, v takovém případě by to ale už asi nebyl jeden server, ale rovnou nějaký distribuovaný systém s mnohem složitější logikou. Pro začátek bude úspěch, když se mu podaří komunikovat s alespoň dvěma klienty. Zbytek je otázka škálování...

Nahoru Odpovědět 16.11.2018 9:52
Pokud spolu kód a komentář nekorespondují, budou patrně oba chybné
Avatar
Odpovídá na Petr Štechmüller
Jiří Hrdina:16.11.2018 10:32

Děkuji za odpověd. Mám v tom docela zmatek. Za jaké situace dojde k bloknutí? Když bude se v jeden čas číst a zároven zapisovat?

 
Nahoru Odpovědět 16.11.2018 10:32
Avatar
Petr Štechmüller
Překladatel
Avatar
Odpovídá na Jiří Hrdina
Petr Štechmüller:16.11.2018 10:42

Ne, jak jsem psal výše, I/O operace jsou "extrémně" časově náročné operace, prostě trvají (o proti řekněme přiřazení proměnné) velmi dlouho. Dále jsou tyto operace synchronní, to znamená, že vlakno musí počkat, dokud se všechna data nezapisou/neprec­tou. Proto je to blokující - musí clse čekat na dokončení tě operace.

Nahoru Odpovědět 16.11.2018 10:42
Pokud spolu kód a komentář nekorespondují, budou patrně oba chybné
Avatar
Odpovídá na Petr Štechmüller
Jiří Hrdina:16.11.2018 12:10

A za předpokladu, že mi to zamrzne, tak to znamená, že nějaké čtení/zápis zablokovalo nějaké vlákno?

 
Nahoru Odpovědět 16.11.2018 12:10
Avatar
Petr Štechmüller
Překladatel
Avatar
Odpovídá na Jiří Hrdina
Petr Štechmüller:16.11.2018 12:11

Jestli Ti zamrzlo GUI, tak to znamená, že tu I/O operaci neprovádíš v samostatném vlákně.

Nahoru Odpovědět 16.11.2018 12:11
Pokud spolu kód a komentář nekorespondují, budou patrně oba chybné
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:16.11.2018 13:25

Ve tvem pripade bych to resil tak, ze

  • klient1 - zpravy send
  • klient2 - zpravy send (pro klient1 je to receive zpravy vlakno)
  • klient1 - stream send
  • klient2 - stream send (pro klient1 je to receive stream vlakno)

Pokud nebude posilat ten druhy stream, tak mu to vlakno neotvirat, takze ti staci 3, mozna.
Mozna by sis vystacil se dvema, kdyby sis domluvil synchronizacni interval pro vlakno pro zpravy.

Editováno 16.11.2018 13:25
 
Nahoru Odpovědět 16.11.2018 13:25
Avatar
Odpovídá na Petr Štechmüller
Jiří Hrdina:18.11.2018 10:35

Tak se mi to podařilo zprovoznit v konzoli, prozatím bez GUI. Nicméně měl bych ještě jeden dotaz. V těch vláknech mám cykly - v read vláknu, ve write vláknu a i v ClientHandler vláknu, což je privátní vnořená třída a toto vlákno se vytváří vždy, když se připojí nový klient. Úplně mi to nepřijde nejlepší, tam mít všude nekonečné cykly - nebo je to v pohodě?

Run metoda ve vnitřní třídě Server - v ClientHandler

@Override
        public void run() {
            while(true){
                try {
                    Message msg = (Message) in.readObject();
                    System.out.println("Přečtená zpráva " + msg);
                    msg.setMessage(msg.getMessage() + " - SENDIMG TO ALL");
                    sendAll(msg);
                } catch (Exception e){
                    System.out.println("Exception in CLIENTHANDLER THREAD");
                }
            }
        }
    }

VLÁKNO PRO POSÍLÁNÍ v Clientovi

Thread sendMessages = new Thread(() -> {

        String fromUser = "";
        BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));

        while(true){
            System.out.println("IN SENDMESSAGES");
            try {
                fromUser = stdIn.readLine();
                Message message = new Message("Peter", null);
                message.setMessage(fromUser);
                System.out.println(message);

                if(fromUser != null){
                    System.out.println("POSÍLÁM NA SERVER" + fromUser);
                    out.writeObject(message);
                }
            } catch (IOException e){
                System.out.println("Exception in SENDMESSAGES thread");
            }
        }
    });

Vlákno pro přijímání zpráv

Thread readMessages = new Thread(() -> {

        Message ms;

        try {
            while (true) {
                ms = (Message) in.readObject();
                System.out.println("Received message " + ms);
            }
        } catch (Exception e){
            System.out.println("EXCEPTION IN READ THREAD");
        }
    });

Děkuji :)

Editováno 18.11.2018 10:36
 
Nahoru Odpovědět 18.11.2018 10:35
Avatar
Petr Štechmüller
Překladatel
Avatar
Odpovídá na Jiří Hrdina
Petr Štechmüller:18.11.2018 10:37

Nekonečná smyčka je v pořádku, ale musíš vytvořit nějaký mechanismus, jak z té smyčky "bezpečně" vylezeš ven. To znamená, že když klient ukončí spojení, nebo to spojení nějakým způsobem "umře", tak musíš ta vlákna zastavit.

Nahoru Odpovědět 18.11.2018 10:37
Pokud spolu kód a komentář nekorespondují, budou patrně oba chybné
Avatar
Odpovídá na Petr Štechmüller
Jiří Hrdina:22.11.2018 21:38

Díky za všechny rady. Dostal jsem se do stádia, kdy pracuji již i s Javou FX.

Mám ze strany treeView, kde se mi načtou všechny online kontakty, když načtu, tak s nimi chci psát, ale pro každého chci mít vytvořený vlastní ListView, který mám vedle těch online kontaktů. Jakým způsobem toho docílit?
Běží mi tam service, který hlídá nové zprávy, které mám uložené v Queue v daném klientovi, ale bohužel se mi to všechno vypisuje do jednoho listView...

Díky :)

 
Nahoru Odpovědět 22.11.2018 21:38
Avatar
Petr Štechmüller
Překladatel
Avatar
Odpovídá na Jiří Hrdina
Petr Štechmüller:22.11.2018 21:40

Bez kódu asi těžko poradím, ale opět tě musím odkázat na místní seriál o tvorbě chatu, který jsem nedavno publikoval. Mělo by tam být vše, co potřebuješ...

Nahoru Odpovědět 22.11.2018 21:40
Pokud spolu kód a komentář nekorespondují, budou patrně oba chybné
Avatar
Odpovídá na Petr Štechmüller
Jiří Hrdina:22.11.2018 21:53

O co mi jde... Jakmile kliknu na někoho, kdo je online, tak mu chci poslat zprávu... což se mi daří, aspon do konzole... jenže se mi nedaří to vypsat do toho listView - aby měla každá konverzace svuj vlastní listView na jedné Stage a aktualizovala zpráva do toho daného listView...

public class Controller extends AbstractController implements Initializable {

    private Client client;
    private Client selectedClient;
    private ObservableList<String> observableList = FXCollections.emptyObservableList();

    @FXML
    private TreeView<Client> treeView;
    private TreeItem<Client> root  = new TreeItem<Client>();

    @FXML
    private ListView<String> mainChat;

    @FXML
    private TextField sendField;

    @FXML
    void sendMessage(ActionEvent event) {
        String msg = sendField.getText();
        System.out.println("MESSAGE " + msg);
        if(msg != null){
            System.out.println("POSÍLÁM ZPRÁVU!!!");
            client.sendMessage(new Message(ServerProtocols.PRIVATE, selectedClient.getId(), selectedClient.getName(), msg));
        }
    }

    public Controller(AccessData accessData) {
        super(accessData);
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        client = getAccessData().getActiveClient();

        treeView.setRoot(root);

        root.setExpanded(true);

        OnlineUsersService onlineUsersService = new OnlineUsersService(client, root);
        onlineUsersService.start(); // PŘIDÁVÁ ONLINE PŘÁTELÉ

        treeView.setOnMouseClicked(e -> {
            selectedClient = treeView.getSelectionModel().getSelectedItem().getValue();
            if(selectedClient != null){
                System.out.println(observableList.size() + "OBS LIST SIZE");
            }
        });

        MessageCheckingService messageCheckingService = new MessageCheckingService(client, observableList, mainChat);
        messageCheckingService.start();
    }
}
public class MessageCheckingService extends Service<Void> {

    private ListView<String> listView;
    private Client client;
    private ObservableList<String> messages;

    public MessageCheckingService(Client client,ObservableList<String> observableList, ListView<String> listView){
        this.client = client;
        this.messages = observableList;
        this.listView = listView;

        listView.setItems(messages);
    }

    @Override
    protected Task<Void> createTask() {
        return new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                while(true){
                    Message m = client.getLastMessage();
                    System.out.println("MESSAGE " + m.getMessage());
                    messages.add(m.getMessage());
                }
            }
        };
    }
}
 
Nahoru Odpovědět 22.11.2018 21:53
Avatar
Petr Štechmüller
Překladatel
Avatar
Odpovídá na Jiří Hrdina
Petr Štechmüller:22.11.2018 22:09

aby měla každá konverzace svuj vlastní listView na jedné Stage

Aby jsi toho docílil, tak máš podle mě 2 možnosti:

  1. při výběru uživatele změníš obsah toho listView na konverzaci s vybraným uživatelem
  2. uděláš si pro každého uživatele listView a podle výběru budeš zobrazovat vybrané listView

Momentálně nemáš implementováno ani jedno, ale 1. možnost bude podle mě snažší.
Ve listeneru na kliknutí do listView treeView.setOn­MouseClicked jenom přidáš refresh konverzace.

Pokud se Ti ty přijaté zprávy vypisují do konzole, ale ne do listView, tak to bude nejspíš tím, že upravuješ grafický prvek (ListView) v jiném, než JavaFX vlákně. Zkus ještě upravit přidání zprávy v tasku:

Platform.runLater(() -> {
    messages.add(m.getMessage());
});
Nahoru Odpovědět 22.11.2018 22:09
Pokud spolu kód a komentář nekorespondují, budou patrně oba chybné
Avatar
Odpovídá na Petr Štechmüller
Jiří Hrdina:22.11.2018 22:26

"Ve listeneru na kliknutí do listView treeView.setOn­MouseClicked jenom přidáš refresh konverzace"

Jak myslíš ten "refresh konverzace" ? Mohl by jsi mi, prosím, trošku uvéct příklad, jak toho docílit, že refreshnu konverzaci?

 
Nahoru Odpovědět 22.11.2018 22:26
Avatar
Petr Štechmüller
Překladatel
Avatar
Odpovídá na Jiří Hrdina
Petr Štechmüller:23.11.2018 13:22

No musíš někde uchovávat celou konverzaci s daným uživatelem. Pak, při změně uživatele jenom na teď danou historii a prepises všechny polozky v tom listView...

Nahoru Odpovědět 23.11.2018 13:22
Pokud spolu kód a komentář nekorespondují, budou patrně oba chybné
Avatar
Odpovídá na Petr Štechmüller
Jiří Hrdina:23.11.2018 14:28

ale tímto způsobem nedocílím toho, že se mi budou zprávy přidávat dynamicky, ne? Jenom pouze, když kliknu na toho klienta, chápu to správně? :)

 
Nahoru Odpovědět 23.11.2018 14:28
Avatar
Petr Štechmüller
Překladatel
Avatar
Odpovídá na Jiří Hrdina
Petr Štechmüller:23.11.2018 14:35

Dynamický by se měly přidávat, protože tu logiku již máš naimplentovanou.

@Override
    protected Task<Void> createTask() {
        return new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                while(true){
                    Message m = client.getLastMessage();
                    System.out.println("MESSAGE " + m.getMessage());
                    messages.add(m.getMessage());
                }
            }
        };
    }
}/code]
Nahoru Odpovědět 23.11.2018 14:35
Pokud spolu kód a komentář nekorespondují, budou patrně oba chybné
Avatar
Odpovídá na Petr Štechmüller
Jiří Hrdina:23.11.2018 14:58

A jakým způsobem by bylo nejlepší ukládat ty zprávy a do jaké kolekce? Na straně kontroleru a v jaké kolekci? Musím nějak rozlišit, jak načíst správnou kolekci, když někdo klikne na nějakého klienta... ty klienti mají svá ID, takže s tím by se dalo pracovat, ale přemýšlím, jak, kam ty kolekce ukládat...

 
Nahoru Odpovědět 23.11.2018 14:58
Avatar
Petr Štechmüller
Překladatel
Avatar
Odpovídá na Jiří Hrdina
Petr Štechmüller:23.11.2018 15:00

To už je otázka tvé vlastní implementace.
Když koukneš na místní tutorial, tak se můžeš inspirovat tam...

Nahoru Odpovědět 23.11.2018 15:00
Pokud spolu kód a komentář nekorespondují, budou patrně oba chybné
Avatar
Odpovídá na Petr Štechmüller
Jiří Hrdina:23.11.2018 15:20

Dobře, díky, mrknu na to zítra. :-) Každopádně bych měl ještě jeden dotaz... Jak moc takováto aplikace by měla žrát CPU? Pokud pustím 3 klienty naráz na jednom ntb a server, tak to teda docela žere opravdu hodně...

 
Nahoru Odpovědět 23.11.2018 15:20
Avatar
Petr Štechmüller
Překladatel
Avatar
Odpovídá na Jiří Hrdina
Petr Štechmüller:23.11.2018 16:11

Jestli to hodně žere, tak je něco hodně špatně. Nemáš tam nějaký poololing?

Nahoru Odpovědět 23.11.2018 16:11
Pokud spolu kód a komentář nekorespondují, budou patrně oba chybné
Avatar
Odpovídá na Petr Štechmüller
Jiří Hrdina:23.11.2018 17:43

Co myslíš pod pooling? Nejsem si toho vědom... Když to pustím, tak jedna žere cca 25% CPU

 
Nahoru Odpovědět 23.11.2018 17:43
Avatar
Petr Štechmüller
Překladatel
Avatar
Petr Štechmüller:24.11.2018 8:03

Pooling - neustálé dotazování klienta serveru, zda-li pro něj nemá nějakou zprávu, ale to snad nebude Tvůj případ.

Nahoru Odpovědět 24.11.2018 8:03
Pokud spolu kód a komentář nekorespondují, budou patrně oba chybné
Avatar
Odpovídá na Petr Štechmüller
Jiří Hrdina:24.11.2018 10:22

Tak jsem na to přišel zřejmě.

Thread sendMessages = new Thread(() -> {

        while(true){
            try {
                while(messagesToSend.size() > 0){
                    Message message = messagesToSend.take();
                    System.out.println("BUDU POSÍLAT ZPRÁVZ");
                    out.writeObject(message);
                }
            } catch (Exception e){
                System.out.println("Exception in SENDMESSAGES thread");
            }
        }
    });

Po tom, co jsem přidal do tohodle vlákna Thread.sleep(3000) za catch, tak mi to žere 0,2-0,8% CPU (Což je z 25% docela slušný skok :-))

Šlo by to asi vyřešit lépe. než ten sleep, že? Ideálně nějakou blokovací metodu, že když nebudou k dispozici zprávy k poslání tak spi...

 
Nahoru Odpovědět 24.11.2018 10:22
Avatar
Petr Štechmüller
Překladatel
Avatar
Odpovídá na Jiří Hrdina
Petr Štechmüller:24.11.2018 10:49

Samozřejmě, že to jde udělat lépe pomocí fronty zpráv.. Prosím, přečti si ten seriál, co tu vyšel, najdeš tam odpovědi na veškeré dosud položené otázky. Tady konkrétně na ten zápis zpráv: https://www.itnetwork.cz/…verem-1-cast

Nahoru Odpovědět 24.11.2018 10:49
Pokud spolu kód a komentář nekorespondují, budou patrně oba chybné
Avatar
Martin Dráb
Redaktor
Avatar
Odpovídá na Jiří Hrdina
Martin Dráb:24.11.2018 10:58

Šlo by to asi vyřešit lépe. než ten sleep, že? Ideálně nějakou blokovací metodu, že když nebudou k dispozici zprávy k poslání tak spi...

Na toto se obvykle používá semafor, což je synchronizační primitivum obsahující jeden interní čítač a dovoluje jeho inkrementaci a dekrementaci. V případě, že se vlákno pokusí onen čítač snížit pod nulu, je uspáno, dokud toto "nebepečí" není zažehnáno (dokud někdo jiný nezvýší čítač tak, že již pod nulu neklesne).

Semafor s čítačem reflektujícím počet zpráv ve front bude dělat přesně to, co potřebuješ.

Nahoru Odpovědět  +1 24.11.2018 10:58
2 + 2 = 5 for extremely large values of 2
Avatar
Odpovídá na Petr Štechmüller
Jiří Hrdina:25.11.2018 16:50

Ahoj, narazil jsem na komplikaci. Podařilo se mi nějak vyřešit ty chaty, uložit do kolekce a načítat i ty správné, podle toho, kdo na co klikne. Nicméně se mi nedaří správně dynamicky updatovat zprávy.
Při prvním chatu, co se vytvoří vše funguje, zprávy se odesílají a vkládají, jakmile přepnu na jiný chat, nějaké zprávy se ztratí a zapíšou se do odlišného listu i přesto, že se vybírá správný list.

Předem děkuji

public class Controller extends AbstractController implements Initializable {

    private Client client;
    private Client selectedClient;
    private ObservableList<String> observableList = FXCollections.emptyObservableList();

    @FXML
    private TreeView<Client> treeView;
    private TreeItem<Client> root  = new TreeItem<Client>();

    @FXML
    private ListView<String> mainChat;

    List<ListView<String>> listViews = new ArrayList<>();

    @FXML
    private TextField sendField;

    @FXML
    void sendMessage(ActionEvent event) {
        String msg = sendField.getText();
        if(msg != null){
            client.sendMessage(new Message(ServerProtocols.PRIVATE, selectedClient.getId(), selectedClient.getName(), msg));
        }
    }

    public Controller(AccessData accessData) {
        super(accessData);
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        client = getAccessData().getActiveClient();

        treeView.setRoot(root);

        root.setExpanded(true);

        OnlineUsersService onlineUsersService = new OnlineUsersService(client, root, getAccessData(), selectedClient);
        onlineUsersService.start();

        treeView.setOnMouseClicked(e -> {
            selectedClient = treeView.getSelectionModel().getSelectedItem().getValue();
            if(selectedClient != null){
                getAccessData().addChat(client.getId(), selectedClient.getId());
                ObservableList<String> chat = getAccessData().getActiveChat();
                System.out.println("Active chat is..." +  chat);
                MessageCheckingService messageCheckingService = new MessageCheckingService(client, getAccessData().getActiveChat(), mainChat);
                messageCheckingService.restart();
            }
        });
    }
}
public class AccessData {

    private Client activeClient;
    private ObservableList<String> activeChat;

    private Map<String, ObservableList<String>> chats = new HashMap<>();


    public Client getActiveClient() {
        return activeClient;
    }

    public void setActiveClient(Client activeClient) {
        this.activeClient = activeClient;
    }

    public ObservableList<String> getChat(int id1, int id2) {
        String value = convertChatID(id1, id2);
        System.out.println("CHCI CHAT S ID " + value);
        if (chats.containsKey(value)) {
            return chats.get(value);
        }
        return null;
    }

    public void addChat(int id1, int id2) {
        String value = convertChatID(id1, id2);
        System.out.println("Nastavuji view---" + value);
        if (!chats.containsKey(value)) {
            ObservableList<String> chat = FXCollections.observableArrayList();
            System.out.println("VKLÁDÁM " + value + " - " + chat);
            chats.put(value, chat);
            setActiveChat(chat);
        } else {
            System.out.println("Chat alredy IN");
            setActiveChat(chats.get(value));
        }
    }

    public ObservableList<String> getActiveChat(){
        return activeChat;
    }

    public void setActiveChat(ObservableList<String> chat) {
        this.activeChat = chat;
    }

    private String convertChatID(int id1, int id2) {
        String value = "";
        // 1; 2
        // 2; 1
        if (id1 < id2) {
            value = id1 + "" + id2;
        } else if (id1 > id2) {
            value = id2 + "" + id1;
        }
        return value;
    }
}
public class MessageCheckingService extends Service<Void> {

    private ListView<String> listView;
    private Client client;
    private ObservableList<String> messages;

    public MessageCheckingService(Client client,ObservableList<String> observableList, ListView<String> listView){
        this.client = client;
        this.messages = observableList;
        this.listView = listView;

        listView.setItems(messages);
    }

    @Override
    protected Task<Void> createTask() {
        System.out.println("STARTING NEW MESSAGECHECKING SERVICE!");
        return new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                while(true){
                    Message m = client.getLastMessage();
                    System.out.println("MESSAGE " + m.getMessage());
                    Platform.runLater(() -> {
                        messages.add(m.getMessage());
                    });
                    System.out.println("OBSERVABLE LIST IN MESSAGESERVICE" + messages);
                }
            }
        };
    }
}
 
Nahoru Odpovědět 25.11.2018 16:50
Avatar
Jiří Hrdina:25.11.2018 18:01
public class MessageCheckingService extends Service<Void> {

    private ListView<String> listView;
    private Client client;
    private ObservableList<String> messages;
    private String id;

    public MessageCheckingService(Client client,ObservableList<String> observableList, ListView<String> listView, String id){
        this.client = client;
        this.messages = observableList;
        this.listView = listView;
        this. id = id;

        listView.setItems(messages);
    }

    @Override
    protected Task<Void> createTask() {
        System.out.println("STARTING NEW MESSAGECHECKING SERVICE!");
        return new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                while(true){
                    Message m = client.getLastMessage();
                    System.out.println("MESSAGE " + m.getMessage());
                    Platform.runLater(() -> {
                        messages.add(m.getMessage());
                    });
                    System.out.println("OBSERVABLE LIST IN MESSAGESERVICE" + messages);
                }
            }
        };
    }
}
 
Nahoru Odpovědět 25.11.2018 18:01
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 32 zpráv z 32.