前回からスレッド周りの制約事項にかかってうまくいっていないけど状況の整理。
やろうとしていることは、前回は表の中にWebsockeで取得したデータを反映しようとしていたものを、Labelに変更して表示しようというもの。
起きているエラーはJavaFXのコンポーネントをJavaFX配下以外のスレッドで呼んではいけないというもの。
スタックトレースは以下。
java.lang.IllegalStateException: Not on FX application thread; currentThread = Grizzly-worker(1)
エラーです:e9e8fea3-96b6-46be-ad8e-a393e1499784
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:237)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:397)
at javafx.scene.Parent$1.onProposedChange(Parent.java:245)
at com.sun.javafx.collections.VetoableObservableList.setAll(VetoableObservableList.java:90)
at com.sun.javafx.collections.ObservableListWrapper.setAll(ObservableListWrapper.java:314)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.updateChildren(LabeledSkinBase.java:602)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.handleControlPropertyChanged(LabeledSkinBase.java:209)
at com.sun.javafx.scene.control.skin.SkinBase$3.changed(SkinBase.java:282)
at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:107)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:196)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:100)
at javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:121)
at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:128)
at javafx.beans.property.StringPropertyBase.access$100(StringPropertyBase.java:67)
at javafx.beans.property.StringPropertyBase$Listener.invalidated(StringPropertyBase.java:236)
at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:155)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:100)
at javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:121)
at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:128)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:161)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:67)
at jp.co.epea.firstfxclient.ObjData.setDataValue(ObjData.java:26)
at jp.co.epea.firstfxclient.WSClient.onMessage(WSClient.java:30)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.glassfish.tyrus.core.AnnotatedEndpoint.callMethod(AnnotatedEndpoint.java:431)
at org.glassfish.tyrus.core.AnnotatedEndpoint.access$100(AnnotatedEndpoint.java:83)
at org.glassfish.tyrus.core.AnnotatedEndpoint$WholeHandler$1.onMessage(AnnotatedEndpoint.java:518)
at org.glassfish.tyrus.core.SessionImpl.notifyMessageHandlers(SessionImpl.java:391)
at org.glassfish.tyrus.core.EndpointWrapper.onMessage(EndpointWrapper.java:498)
at org.glassfish.tyrus.container.grizzly.GrizzlyClientSocket.onMessage(GrizzlyClientSocket.java:393)
at org.glassfish.tyrus.websockets.frametypes.TextFrameType.respond(TextFrameType.java:66)
at org.glassfish.tyrus.websockets.DataFrame.respond(DataFrame.java:102)
at org.glassfish.tyrus.container.grizzly.WebSocketFilter.handleRead(WebSocketFilter.java:300)
at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114)
at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:837)
at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:565)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:545)
at java.lang.Thread.run(Thread.java:724)
現在の書き方(ソース)でかかっている場所は、ClientManager#connectToServerでGrizzlyのスレッドがたっていて、
@Override protected Task createTask() { Task<Void> task = new Task<Void>() { @Override protected Void call() throws Exception { try { URI clientURI = new URI("ws://localhost:8080/first/hello/"); ClientManager cliContainer = org.glassfish.tyrus.client.ClientManager.createClient(); cliContainer.connectToServer(new WSClient(data), clientURI); } catch (DeploymentException ex) { Logger.getLogger(SampleController.class.getName()).log(Level.SEVERE, null, ex); } return null; } }; return task; }
その中で動いているOnmessegeで値を書き換えようとしていること
ObjData data; @OnMessage public void onMessage(String message) { if (message.length() == 0) { return; } System.out.println(data.getDataValue()); data.setDataValue(message);//下の自分で作ったメソッド System.out.println(data.getDataValue()); } // ObjDataの中 private SimpleStringProperty dataValue; public void setDataValue(String dataValue) { dataValueProperty().set(dataValue); }
改めて前回サンプルにしたソースを見直すとObservableListの変更をトリガーにした通知機能をうまく使っているみたい。
なお、自前でスレッドを管理している場合のドキュメントはこちら