JavaFX Multithreading Concept - java

Before I start: I'm a newbee in JavaFX and with this project i want to learn how to use this library properly.
The situation is the following: i have a server-client application. The server sends the client a list of the active users on the server. Now i want to list the active users in the UI. I wanted to do that with buttons in FlowPane. The problem is that my client is in an external thread, so not in the application-thread. But because of the fact that the client gets the list on users, I tried to update the button-list directly from the client-thread.
if(data.getObject() instanceof ArrayList<?>) {
ArrayList<User> activeUsers = (ArrayList<User>) data.getObject();
controller.setActiveUsers(activeUsers);
}
The method in my controller does the following:
public void setActiveUsers(ArrayList<User> activeUsers) {
for(User user:activeUsers) {
fpOnlineUsers.getChildren().add(new Button(user.getName()));
}
}
The Exception i get is the following:java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-3
I have two questions:
How can i fix this?
Why blocks JavaFX changed made from threads other than the application-thread?
Please apologize any language mistakes, I'm not a native speaker :)

You need to make any JavaFX object related calls on the Application Thread. To do this from your client Thread use the Application.runlater(Runnable) function.
Your code should look something like this:
public void setActiveUsers(ArrayList<User> activeUsers) {
Platform.runLater(new Runnable() {
#Override public void run() {
for(User user:activeUsers) {
fpOnlineUsers.getChildren().add(new Button(user.getName()));
}
}
}
});
Reference:
Platform.runLater and Task in JavaFX

Related

Android UI Thread stop other Threads

I have a code in the UI Thread that call to another Thread. This new Thread wait for a server response to execute an database update.
When the new Thread send the post content the server send the answer fine, but the update process to the database stops when the screen (activity) load the next item to calculate and send it to the server again.
My code looks like this
public class MyActivity extends Activity {
onCreate(){ ... }
public void pushButton(View v) {
...
//Call the Thread
MyOwnThread t = new MyOwnThread(arg1, arg2);
t.start();
showTheNextItemToProcess();
}
}
MyOwnThread looks like this
public class MyOwnThread extends Thread {
public MyOwnThread(String arg1, Object arg2) { ... }
public void run() {
if(arg1.equals("ok_status") {
//The code on this part stops wen the UI Thread show the next item to process
for( ... ) {
// ...
}
}
}
}
I tried with send a clone of the variables inside the new Thread constructor, but the result it's the same. I don´t know why the UI Thread interrupts the another Thread. With the ListenableFuture (Google Guava) it´s the same.
ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1));
ListenableFuture<String> futureTask = service.submit(new Callable<String>(){
public String call() {
//Send the post to the server
}
});
Futures.addCallback(futureTask, new FutureCallback<String>() {
#Override
public void onSuccess(String arg0) {
//when get the answer from the server, executes the db update
//the UI thread stop this too
}
});
I don't see errors in the LogCat. Your help is welcome, sorry for my bad english.
Thanks!
EDIT
I changed my code to use full threads (extends Thread), with WIFI connection the app sends the package to the server and the server returns the response, the app takes the value sended from the server and trigger the db update, it's fine!. But with the movil data (local operator), the app calls and runs the Thread but the thread simply not continue running. I had set the priority to MAX and it's the same. Anyone know why????
Thanks!

Runnable concurrency

I am playing around with JMonkeyEngine.
While doing this i play JavaFX MediaPlayer.
This MediaPlayer takes a Runnable to handle what's to do, when the media finished:
mp.setOnEndOfMedia(new Runnable() {
#Override public void run() {
}}
I want to do sth. like this:
mp.setOnEndOfMedia(new Runnable() {
#Override public void run() {
// instance.toggleLists();
initMediaPlayer(mediaView, actualList.getPath()+actualList.getMediaLocation());
detachChild(node);
node = new TextureNode("mediaManagerTextureNode");
node.init(app, mp);
attachChild(node);
}
});
this is working a couple of times, but finally i am running into some runtime error.
java.lang.IllegalStateException: Scene graph is not properly updated for rendering.
State was changed after rootNode.updateGeometricState() call.
Make sure you do not modify the scene from another thread!
Problem spatial name: Root Node
Yeah, that's true. I am messing up that thread from the outside.
As i am a little bit unused to this stuff...
I don't need to do that thing at that location in that run method, it's just what has to be done,when this is running.
What is the best way to pass over the work so that my ordinary update call can do that housework ?
I already tried to build in a flag, setting that to true and when true, updating that by the standard update call from the application itself, but somehow i ever run into this error. That didn't help me much.
The MediaPlayer just needs to tell my App "Hey! I'm ready! Give me a break and change me to something new!"
That is, what is happening in that run method.
You can use Application.enqueue to make a Runnable run on the main thread in the next update - like so: (assuming app is a reference to the Application)
mp.setOnEndOfMedia(new Runnable() {
#Override public void run() {
app.enqueue(new Runnable() {
#Override public void run() {
initMediaPlayer(mediaView, actualList.getPath()+actualList.getMediaLocation());
detachChild(node);
node = new TextureNode("mediaManagerTextureNode");
node.init(app, mp);
attachChild(node);
}
});
}
});
If you're using Java 8, you can abbreviate this using lambda expressions:
mp.setOnEndOfMedia(() -> {app.enqueue(() -> {
initMediaPlayer(mediaView, actualList.getPath()+actualList.getMediaLocation());
detachChild(node);
node = new TextureNode("mediaManagerTextureNode");
node.init(app, mp);
attachChild(node);
}});

Single Android Thread for Multiple Jobs

I would like to have an application which either loads or saves data through a HTTP request, however the data must interact with the UI thread. Ideally, I would like a single thread to use an IF statement on a message to determine if the request is to "load" or "save".
What would be the simplest way of doing this with the smallest amount of code?
Also, do instances of Handlers run on individual threads?
EDIT: This is the code I am using now:
Handler doStuff = new Handler(){
#Override
public void handleMessage(Message msg){
if(msg.what == 1){
// Load all the information.
// Get the ID from sharedPrefs
SharedPreferences details= getSharedPreferences("details", 0);
String ID = patDetails.getString("id", "error");
// Load up the ID from HTTP
String patInfo = httpInc.getURLContent("info.php?no="+AES.encrypt("387gk3hjbo8sgslksjho87s", ID));
// Separate all the details
patientInfo = patInfo.split("~");
}
if(msg.what == 2){
// Save the data
}
}
};
Eclipse halts the debugging and displays, "Source not found" for StrictMode.class
I suppose it's because it's using the Main thread to access the internet although it's running in individual threads.
Any idea.
Handlers do run on individual threads. Check that link. You should also check out AsyncTask.
I would propose submitting the jobs as Runnable to a single-threaded ExecutorService:
public class SomeClass {
private ExecutorService execService = Executors.newSingleThreadExecutor();
public void doSomething() {
final String someUiData = // retrieve data from UI
execService.submit(new Runnable() {
#Override
public void run() {
// so something time-consuming, which will be executed asynchronously from the UI thread
// you can also access someUiData here...
}
});
}
}
This way, the UI thread will not block whereas you can easily submit a different Runnable for different operations and the ExecutorService will completely take care of keeping it async.
Edit: If you need to interact with the UI, do so before becoming asynchronous and keep the result in final variables.

How to pass the message from working thread to GUI in java

How to pass the message from working thread to GUI in java? I know in Android this can be achieved through handlers and Messages Class. But I want the same thing in Java can any one help me.
Thanks in advance.
Ranganath.tm
You must use SwingUtilities.invokeLater, because Swing components must only be accessed from the event dispatch thread.
The javadoc of this method has a link to the Swing tutorial about threads. Follow this link.
Here's an example:
public class SwingWithThread {
private JLabel label;
// ...
public void startBackgroundThread() {
Runnable r = new Runnable() {
#Override
public void run() {
try {
// simulate some background work
Thread.sleep(5000L);
}
catch (InterruptedException e) {
// ignore
}
// update the label IN THE EDT!
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
label.setText("Background thread has stopped");
}
});
};
};
new Thread(r).start();
}
}
I think that the best way to do so is to use EventBus & MVP design for your GUI components. "Working thread" fires event by sending it to bus, and Presenters which are handlers for particular type of event, are notified about it.
Nice description of such design can be found here:
Is there a recommended way to use the Observer pattern in MVP using GWT?
...although question is about GWT answer is applicable to all applications designed according to MVP.
Send events. See this tutorial
We do it like this on FrostWire, through this utility function we can check if the runnable/thread you're using is being invoked already from the GUI thread
/**
* InvokesLater if not already in the dispatch thread.
*/
public static void safeInvokeLater(Runnable runnable) {
if (EventQueue.isDispatchThread()) {
runnable.run();
} else {
SwingUtilities.invokeLater(runnable);
}
}
You can use SwingWorker class, its designed to address this case:
http://download.oracle.com/javase/tutorial/uiswing/concurrency/worker.html

Android: Best practice for responsive user interfaces

I am quite new to Android and Java. Before I was working with C++ where the events where dispatched with messages. Now I would like to create the same user experience for Android platform and I would appreciate any of your suggestions or comments on what is the best way to bind events to user controls.
Here is an example from C++:
ON_MESSAGE(WM_RECORD_START, &CMainFrame::OnRecordStart)//Method OnRecordStarts() executes on WM_RECORD_START_MESSAGE
...
LRESULT CMainFrame::OnRecordStart(WPARAM wParam, LPARAM lParam)
{
m_pNetworkCtrl->SetGeoLocationInfo();
...
}
...
void CMainFrame::RecordStart()
{
PostMessage(WM_RECORD_START);
}
In the case above the method RecordStart() is bound to a Button (it is executed when a Button is pressed) and posts the message WM_RECORD_START. When the message WM_RECORD_START is received, the method OnRecordStart() is executed.
As mentioned before I would like to create a responsive user interface and am not sure if it would be good enough if the method OnRecordStart() is called directly from RecordStart():
void RecordStart()
{
OnRecordStart();
}
I would really appreciate any of your suggestions.
You can emulator the MFC style behavior in Android by using a Handler to post a Runnable into the message queue.
Here is a brief example
class MyClass
{
Handler m_myHandler;
Runnable m_myRunnable;
MyClass()
{
m_myHandler = new Handler();
m_myRunnable = new RUnnable()
{
public void run()
{
// do your stuff here
}
};
}
public void onclickListener(...)
{
// push the runnable into the message queue
m_myHandler.post(m_myRUnnable);
}
}
You have 2 questions here.
How to bind controls. I use
anonymous inner classes everywhere. It is a bit verbose to type in but auto completion makes it a snap.
how to make the UI responsive.
The key is not to do anything time
consuming in the UI thread. If it
takes more than .1s, do the work in
a worker thread and notify the UI to
update when the task is done. The
other thing is to make sure you
don't generate a lot of garbage
since the android GC is pretty primitive right now.
For Buttons I usually extend Button class and override onTouchEvent()
public boolean onTouchEvent (MotionEvent event)
{
if (event.getAction() == MotionEvent.ACTION_DOWN)
{
setPressed(true);
}
return super.onTouchEvent(event);
}

Categories

Resources