I'm trying to do a simple chat application on javafx
my actual problem is the thread to insert updates into a observablelist and set it on a listview
the code im using :
String message_reçu;
try {
out = new PrintWriter(socket.getOutputStream());
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (true) {
message_reçu = in.readLine();
if (message_reçu != null) {
messagesReçus.add(message_reçu);
}
if (message_reçu.equals("QUIT")) {
break;
}
}
in.close();
out.close();
socket.close();
I did this inside of a runnable class and once the server fire a msg the thread insert the msg on the list and shows on the listview but the thread dies instead of keep the work
I did a search on it and every one says to use a runlater but I’m completely lost there I did declare a runlater but I’m not sure how to execute it so any help is welcome
Thanks
Other Answers
This question is largely a duplicate of the following questions, so also refer to the answers to those:
Usage of JavaFX Platform.runLater and access to UI from a different thread
Platform.runLater and Task in JavaFX
Solution
Your question is little more specific than those though, so I'll provide some extra info.
For your particular code you want to wrap the add call in Platform.runLater:
Platform.runLater(new Runnable() {
public void run() {
messagesReçus.add(message_reçu);
}
});
Everything else in your example stays as it is.
Background Information
JavaFX UI updates must be made on the JavaFX application thread or there is a high likelihood that your program will malfunction in unexpected ways.
The ListView control listens for changes to the ObservableList backing the ListView cell values. When that list changes, a UI update is immediately triggered on the thread the originally updated the list.
Once you wrap the list modifications in Platform.runLater, you ensure that the subsequently triggered UI update is performed on the JavaFX application thread rather than your user thread.
Related
I would like someone to explain to me what is Device.BeginInvokeOnMainThread and what is it for?
And also some examples of cases where it's used.
Just to add an example.
Imagine you have an async method DoAnyWorkAsync if you call it (just as an example) this way:
DoAnyWorkAsync().ContinueWith ((arg) => {
StatusLabel.Text = "Async operation completed...";
});
StatusLabel is a label you have in the XAML.
The code above will not show the message in the label once the async operation had finished, because the callback is in another thread different than the UI thread and because of that it cannot modify the UI.
If the same code you update it a bit, just enclosing the StatusLabel text update within Device.BeginInvokeOnMainThread like this:
DoAnyWorkAsync().ContinueWith ((arg) => {
Device.BeginInvokeOnMainThread (() => {
StatusLabel.Text = "Async operation completed...";
});
});
there will not be any problem.
Try it yourself, replacing DoAnyWorkAsync() with Task.Delay(2000).
The simple answer is: Background thread cannot modify UI elements because most UI operations in iOS and Android are not thread-safe; therefore, you need to invoke UI thread to execute the code that modifies UI such MyLabel.Text="New Text".
The detailed answer can be found in Xamarin document:
For iOS:
IOSPlatformServices.BeginInvokeOnMainThread() Method simply calls NSRunLoop.Main.BeginInvokeOnMainThread
public void BeginInvokeOnMainThread(Action action)
{
NSRunLoop.Main.BeginInvokeOnMainThread(action.Invoke);
}
https://developer.xamarin.com/api/member/Foundation.NSObject.BeginInvokeOnMainThread/p/ObjCRuntime.Selector/Foundation.NSObject/
You use this method from a thread to invoke the code in the specified object that is exposed with the specified selector in the UI thread. This is required for most operations that affect UIKit or AppKit as neither one of those APIs is thread safe.
The code is executed when the main thread goes back to its main loop for processing events.
For Android:
Many People think on Xamarin.Android BeginInvokeOnMainThread() method use Activity.runOnUiThread(), BUT this is NOT the case, and there is a difference between using runOnUiThread() and Handler.Post():
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);//<-- post message delays action until UI thread is scheduled to handle messages
} else {
action.run();//<--action is executed immediately if current running thread is UI thread.
}
}
The actual implementation of Xamarin.Android BeginInvokeOnMainThread() method can be found in AndroidPlatformServices.cs class
public void BeginInvokeOnMainThread(Action action)
{
if (s_handler == null || s_handler.Looper != Looper.MainLooper)
{
s_handler = new Handler(Looper.MainLooper);
}
s_handler.Post(action);
}
https://developer.android.com/reference/android/os/Handler.html#post(java.lang.Runnable)
As you can see, you action code is not executed immediately by Handler.Post(action). It is added to the Looper's message queue, and is handled when the UI thread's scheduled to handle its message.
You can only update the UI from the main UI thread. If you are running code on a background thread and need to update the UI, BeginInvokeOnMainThread() allows you to force your code to run on the main thread, so you can update the UI.
As explained above, any UI updates must happen in the main thread or an exception will occur.
Though there's a peculiarity with Xamarin.Forms, one can manilpulate UI elements (e.g. create Labels and add them to StackLayout's Children collection) off the main thread without any failures as long as this part of UI is detached from UI elements currently displayed. This approach can be used to boost performance by creating Xamarin.Forms controls and setting their child/parent relations in-memory/off-screen in a separate thread BUT in order to attach them to displayed container (e.g. assign ContentPage's Content property) you will have to do this in Device.BeginInvokeOnMainThread().
While analysing the relationship between UI thread and background thread in some situation, we should be aware of the following:
BeginInvokeOnMainThread method as described in the docs, merely queues the invocation and returns immediately to the caller. So in this case, UI thread and background thread which submitted some work to UI thread, might work in parallel.
However, there is also InvokeOnMainThread which, as described in the docs, waits for the UI thread to execute the method, and does not return until the code pointed by action has completed. So in this case, background thread waits for UI thread to finish executing the given work, and then background thread continues execution.
In WPF, there is a Closing event on <Window... tag, where we can hook up some dispose code in MainWindow_OnClosing.
But there is no such event in UWP app. The closing I guess is Unloaded, not even Unloading is there.
I just placed my disposing code there but still feel concerned. Is Unloaded event supposed for this type of work? Is there something I need to take note?
According to the MSDN, the Window class has a Closed event.
I'm mentioning this as you posted the Closing event of a window component, but keep in mind the remark of the event:
The Closed event occurs when a Window closes. However, Windows Store
apps typically use a single Window instance, and do not open and close
additional Window instances.
Now, when using the Frame navigation system of the main window with Pages, I advise you to use the OnNavigatedTo and OnNavigatedFrom events to manipulate all initialisation and dispose functionality of the class.
You may want to pay attention to the OnNavigationFrom as it is invoked immediately before the Page is unloaded and is no longer the current source of a parent Frame.
A really simple example:
Windows.ApplicationModel.Resources.ResourceLoader loader;
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
loader = new Windows.ApplicationModel.Resources.ResourceLoader();
var navigationPageContentFormat = loader.GetString("NavigationPageContent");
var navigationPageContentWhenEmpty = loader.GetString("NavigationPageContentWhenEmpty");
this.ParameterTextBlock.Text = String.Format(navigationPageContentFormat, e.Parameter?.ToString() ?? navigationPageContentWhenEmpty);
}
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
loader = null;
}
I am using a Thread in Spring mvc project to do some background working.
What I have done is
I write a class which extends Thread. and I added init() method to start this class.
Whole ThreadTest.java is Below.
package org.owls.thread.vo;
public class ThreadTest extends Thread {
public void init(){
this.start();
}
public void pause(){
this.interrupt();
}
#Override
public void run() {
for(int i = 0; i < 100; i++){
try{
Thread.sleep(3000);
System.out.println("Thread is running : " + i);
} catch(Exception e){e.printStackTrace();}
}
}
};
edit root-context.xml intent to start this Thread as soon as possible when the server started.
<bean id="threadTest" class="org.owls.thread.vo.ThreadTest" init-method="init"/>
Now is the problem. I want to make a toggle button(pause/resume) in my home.jsp and When I click the button it works. But I do not know how can I access to the Thread, which already registered and run.
please, show me the way~>0<
P.S
additional question about java Thread.
What method exactly means pause and resume. I thought stop is the one similar to pause, but it is deprecated.
And start() is somehow feels like 'new()' not resume.
Thanks
I figured out how to control a thread.
if I want to pause(not stop), code should be like below.
thread.suspend();
And want to resume this from where it paused, like below.
thread.resume();
even though those methods are both deprecated.
(if somebody knows some replacement of these, reply please)
If you do not want to yellow warning in your spring project,
you can remove warning by simply add an annotation on that method.
annotation is #SuppressWarnings("deprecated").
=========================================================
From here, additional solutions based on my experience.
To make automatic executing Spring mvc Thread,
I did following steps.
make a simple Class which extends Thread class.
inside that class, make a method. this will be calles by
config files. in this method. I wrote code like "this.start();".
Let Spring knows we have a Thread class that should run independently
with Web activities. To do this, we have to edit root-context.xml.
Add a bean like this.
<bean id="threadTest" class="org.owls.thread.vo.ThreadTest" init-method="init"/>
init is the method name which generated by user in step 2.
Now we run this project Automatically Thread runs.
Controlling Thread is not relavent with Spring, I guess.
It is basically belongs to java rules.
I hope this TIP(?) will be helpful to people who just entered world of programming :-)
How can you make a background web request and then update the UI, but have all the code that does the web requesting/parsing in a separate class so you can use it in multiple places? I thought I could use the classes methods as event handlers for a BackgroundWorker class, like
APIHelper mHelper = new APIHelper("http://example.com?foo=bar");
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork +=new DoWorkEventHandler(mHelper.GetResponse);
bw.RunWorkerCompleted +=new RunWorkerCompletedEventHandler(mHelper.HandleResponse);
bw.RunWorkerAsync();
where APIHelper has the method
public void GetResponse(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = (BackgroundWorker) sender;
WebRequest request = HttpWebRequest.Create(this.URL);
IAsyncResult result = (IAsyncResult)
request.BeginGetResponse(ResponseCallback, request);
}
but then I don't know how to access the worker thread from ResponseCallback and, anyway, HandleResponse gets called first (obviously). (I tried putting in result.AsyncWaitHandle.WaitOne(); but I get a NotSupportedException error.) Yet I can't work out how to make the web request call synchronously. I'm clearly trying to go about this the wrong way, but I have no idea what the right way is.
ETA:
My aim is to be able to go:
user clicks (a) button(s) (on various pages)
a "working" message is displayed on the UI thread (and then input is blocked)
in a background thread my APIHelper class makes the relevant API call, gets the response, and passes it back to the UI thread; I only seem to be able to do this by starting another thread and waiting for that to return, because there's no synchronous web requests
the UI thread updates with the returned message (and input continues as before)
I can do the first two bits, and if I have the response, I can do the last bits, but I can't work out how to do the middle bit. Hopefully that made it clearer!
It took me several tried before I found there is a Dispatcher.
During the BackgroundWorker's dowork and complete methods you can call:
this.Dispatcher.BeginInvoke(() =>
{
// UPDATE UI BITS
});
I think the Dispatcher is only available in the view. So I'm not sure if the methods can exist outside of the xaml.cs
Put whatever you want to update in your UI; when updating an ObservableCollection you must do the update of you items in the Dispatcher.BeginInvoke too
This link might be a good read too:
http://www.windowsphonegeek.com/articles/All-about-Splash-Screens-in-WP7-ndash-Creating-animated-Splash-Screen
Update to assist notes
This is just a rough idea mind you...
bw.DoWork +=new DoWorkEventHandler(DoWork);
bw.RunWorkerCompleted +=new RunWorkerCompletedEventHandler(Complete)
// At least I think the EA is DoWork....
public void DoWork(object sender, DoWorkEventArgs e)
{
mHelper.GetResponse();
this.Dispatcher.BeginInvoke(() =>
{
UIObject.Visibility Collapse.
});
// Wait and do work with response.
});
}
public void Complete(object sender, RunWorkerCompleteEventArgs e)
{
this.Dispatcher.BeginInvoke(() =>
{
UIObject.Visible ....
});
}
I'd put all this logic in a viewmodel that the viewmodel of each page inherits from.
Have the pages bind to properties on the viewmodel (such as ShowLoading, etc.) which the model updates appropriately. i.e. before making the webrequest and in the callback.
As you won't be running the viewmodel code in the UI thread you also wouldn't need to run in a separate BackgroundWorker and you'll be able to access the properties of the viewmodel without issue.
It might be useful if you use a helper class that I have developed for WebDownload purposes during WP7 development.
I'm using it in 2-3 WP7 apps and no problem so far. Give it a go to see if it helps. You can get the class from the my blog linked bellow:
http://www.manorey.net/mohblog/?p=17#content
[NOTE] When working with this class you don't need to run anything in a background worker or new thread; it handles it all asynchronously.
Mobile app provides the user with the option of downloading the email attachment from remote.Connecting with a remote server and downloading the content is carried out in a separate thread.A dialog is shown to the user with cancel command.Herewith I am providing the pseudo code.
new Thread(new Runnable()
public void run(){
try{
//open connection to remote server
//get data input stream
//create byte array of length attachment size
//show modeless dialog with the message "Downloading..."
for(int i=0;i<attachmentSize;i++){
//set the progress indicator of the modeless dialog based upon for iteration
//read the byte from input stream and store it in byte array
}
//open file connection outputstream and store the downloaded content as a file in mobile file system
//show dialog with the message "attachment successfully downloaded"
}
catch(IOException ioe) { }
catch(Exception ex) { }
}
).start();
Now I'm in the process of adding cancel command to the dialog with progress indicator. When the user clicks "Cancel" command in mobile, modeless dialog can be disposed by calling dispose() method. How can I abruptly stop the thread which gets the email attachments via streaming?
Please do help me to resolve this issue.
You can stop it abruptly - but it brings more trouble that it's worth.
The canonical way of doing this is to have a flag which is checked in the Runnable:
public class ClassHoldingRunnable {
private volatile boolean stopRequested = false;
public void executeAsync() {
Runnable r= new Runnable() {
public void run() {
while ( !stopRequested ) {
// do work
}
}
}
new Thread(r).start();
}
public void cancel() {
stopRequested = true;
}
}
A few notes:
it's vital for the stopRequested flag to be either volatile or to have another visibility guarantee ( synchronized, Lock, Atomic ) since it's being accessed by multiple threads;
you should check for stopRequested pretty often if it's important for the end user to have a responsive GUI;
There are several complimentary ways to interrupt a Thread that reads from a Connection.
You are probably reading the remote data by looping over a single call to InputStream.read, so you can reuse a single, relatively small, byte[] object. You can check a boolean member variable before each iteration. You don't really need to synchronize around that boolean because it is only supposed to change value once after Thread construction.
closing the Connection means that your Thread will throw a IOException when it next tries to access it. A proper JavaME implementation will not make Connection.close() block even if another Thread is reading from the Connection's InputStream.
I am not an expert on this so take my suggestion with a grain of salt, as my experience is very limited on Java threads.
You cannot stop a running thread. You can just exit it as soon as possible. So what you could do is to have, for example, a shared flag that you test periodically in the secondary thread. When the main thread sets it in response to a Cancel click, the secondary thread returns.
My experience is more in C# but this might still be applicable...
I don't think it's a good idea to find some way of just "killing a thread" any more than you would just delete an object and skip its destructor.
You could tell the thread to commit suicide via an interrupt. You can then either use the thread's interrupted flag as the indicator or, if you have a sleep/wait in there, you could catch an interrupted exception and shut down properly when this is caught (in the finally block). This should provide, more or less, what you're looking for.