I just try to show a loading-animation while I access an ERP in my code like this:
protected void submit()
{
messageField.getStyleClass().add("smallLoading");
submitImpl();
messageField.getStyleClass().remove("smallLoading");
}
Sadly the animation is never shown... Just the result as before. I tried using Platform.runLater, which yielded the same result. I also transfered the last 2 lines in a Thread, which worked (the animation was shown), but lead to the error "Not on FX application thread", when the Submitter tried to write to my message-field. When I passed the Thread to Platform.runLater it did not show the animation... I googled a little bit, but could not find a solution. Maybe I'm missing something important...
I appreciate any help. Thank you!
It seems like you don't really fully understand how the UI thread works.
The code you've posted is single-threaded. It all operates on the UI thread. You add a style class, do some work, then remove it. The problem is that this sequence of operations is effectively "atomic": the UI doesn't actually update anything until its all done. This is why you don't see the loading symbol change.
When you put all of this within runLater the result is the same. It's still all on the UI thread. The only difference here is that rather than running the code now, you're deferring it until some point "later" (probably actually very soon).
When you try to put the last two lines in a separate thread, the issue is that you're trying to make UI changes on a non-UI thread. That's not allowed.
What you want to do is run everything on a non-UI thread, and push back the UI operations to the UI thread with runLater. Something like this:
new Thread(() -> {
Platform.runLater(()-> messageField.getStyleClass().add("smallLoading"));
submitImpl();
Platform.runLater(()-> messageField.getStyleClass().remove("smallLoading"));
}).start();
Related
I got an AsyncTask for URL connection. Now I want to have a loading spinner everytime I do the URL connection. I display the loading spinner in onPreExecute() and dismiss it in onPostExecute.
I tested this with an endless while loop in doInBackgroung().
The big problem is the GUI is freezing and the loading spinner is not shown.
In my opinion the reason is URLconnection.execute().get(). But I need the get() because the activity need the result to working with it.
My question is now: What is the best way to do this to achieve my wishes? (By the way it is not important to get a solution with an "AsyncTask solution" because there are maybe better solutions and AsyncTask will be deprecated with SDK version 30)
Thank you very much and stay healthy!
As you said AsyncTask will be deprecated.
So it is better to go for an alternative.
Since you mentioned you are not relying on AsyncTask, I will present to you another approach.
Let me introduce you to coroutines and convince you that they will solve your problem and "get the job done".
When I got to know about coroutines, this video was one of the first example that has demonstrated to me the potential of using coroutines in my app. At that point I was still using 100% Java, probably like you are right now.
The good part is: getting started with Kotlin is really easy! Not only you can call Kotlin functions from Java Code, you can also call Java functions from Kotlin code.
To "do something in background" in Kotlin, all you need to do is to launch a coroutine (on a background thread).
Do you have a ViewModel to fetch your data? If it is an option to transfer this file to kotlin, then starting (and scoping) a coroutine becomes as simple as this.
For fragments or activitities you could use other copes as well. However, using the global scope is usually discouraged.
Executing coroutines is as simple as that:
class MyViewModel: ViewModel() {
fun loadDataInBackgroundAndShowSpinner {
viewModelScope.launch {
// Coroutine that will be canceled when the ViewModel is cleared.
// start your spinning
// do all the heave data work on a background thread
doInBackground()
// end your spinning here
}
}
suspend fun doInBackground(inputURL: String) {
withContext(Dispatchers.IO) {
// Execute all your data fetching here
...
// Assign your data to your viewModel variables, post it to a LiveData object, etc.
}
}
}
You do not need any loops in the main thread or anything. By using withContext on a background thread you can achieve main-safety.
Within a launched coroutine, everything (by default) gets executed in order.
Still you will not block the Main Thread. How did you achieve that?
The key here is that your doInBackground function has the suspend keyword. Therefore your loadDataInBackgroundAndShowSpinner on the main thread will "suspend" your doInBackground function and the main thread is able to do whatever you want (i.e. nothing freezes). Then, once your doInBackground is finished, it will resume execution and you can just dismiss your spinner again on the main thread.
Kotlin coroutines make it so much easier to do something in the background and I really want to encourage you to give it a try! It will definitely solve your problem and I can not think of a more easy way.
Google also tried to make it as easy as possible to get you started when coming from Java.
Helo guys!
I am new to JavaFX. I am writing really small application which simulates working of printer. Simulation is running on special thread called PrintingProcess (this process is doing only one thing - waits given time and then increment counter). I need to send this value to window, where labels should show how many pages was "printed". Is any way to do it? So far I wrote small singleton class to hold value.
[edit] I solved it using tasks :) thanks for help
You should use the Task.updateProgress method. Call it to specify the current percentage of pages printed. Override Task.call to perform the action which needs to run in another thread. This method should never manipulate a JavaFX component. You can then oerride methods such as Task.succeeded to implement the behaviour of your UI when the print job is over. Look at the doc of this class to fully take advantage of it.
Platform.runLater(new Runnable() {
#Override public void run() {
textLabel.setText(yourValue);
}
});
The example above is quite simple. You ask JavaFX a runnable as soon as it can. I don't know how that works exactly but that's the way to change UI components from a non-JavaFX thread.
You could pass textLabel variable to any thread with a custom class or a new anonymous thread.
EDIT:
I find Dici's answer more appropriate for your application. I wouldn't recommend putting this code in any loop incase you may still use this.
I'm trying to optimize my android app, it's a big app and it's taking a lot of battery while running. So I'm trying to see what I can do to fix that.
I ran DDMS and looked at the threads, there are a lot : almost 30. The ones I create through instances of AsyncTask are in "Wait" state. In my code I create them, run some code in "doInBackground" and never touch them again.
From what I understand so far, it means they are done working for now, and something called "Object.wait()" on them.
So first : What is this something, how does it works ?
And : Every time I want my code to run in a new Thread, I create a new AsyncTask instance. Does this "something" wake the old thread, or should I keep a trace of the thread, destroy it when I'm done ?
Thanks for helping me understand.
The page
http://developer.android.com/guide/components/processes-and-threads.html
tells that "To use it, you must subclass AsyncTask and implement the doInBackground() callback method, which runs in a pool of background threads. "
So as a matter of fact AsyncTasks will reuse the old threads.
I'm trying to teach myself JavaFX and stumbled over a problem I can't seem to fully understand even after reading anything remotely related I could find.
What I'm trying to do :
I basically want to run some quick processing in the background of my JavaFX application so to not block the UI for the user. While this is happening a UI element is put up which then should be removed as soon as the background process is finished.
So what I attempted to do was to just move those method calls into a Task which should then run without making the UI freeze.
Task task = new Task<Void>() {
#Override
protected Void call() {
step1();
step2();
step3();
}};
new Thread(task).start();
I want to call multiple methods of the class we're currently in, but what's happening instead is that only the first method gets invoked. It seems to me that after step1 has reached it's end it doesn't actually "return" to the Task. I've tried looking up how this works and what I could do but honestly didn't get any smarter. Basically all examples of threading and workers only included how to loop and do recurring things but I really just want a "single execution" but in background.
It's probably a really idiotic thing I'm trying to do and shows my little understanding of this but if anyone could point me into the right direction I'd be very thankful.
Thanks a lot!
Solution :
When working with JavaFX the use of "Platform.runLater(task)" is advisable since a normal Thread cannot interact with the UI. A IllegalStateException will be thrown and the thread is halted/canceled(?). The Task itself can remain unchanged but has to be handed to the Platform to execute it to prevent this issue. I changed that one line and everything was perfect afterwards.
I hope this might help someone, someday :-)
I'm new to the idea of Threading, but not asynchronous behavior. My Android app is taking ~180 millisecond to start up and ~550 milli when I use GoogleAnalytics trackViewPage method and MobFoxView constructor. Coming from Actionscript 3, anything that "took time" was automatically async and I was forced to handle it with listeners which is a bit different in Android it appears. It seems I'M responsible for deciding when something should be asynchronous. So I guess my question is, HOW do I decide what should be async? Is it by milliseconds of executing? But perhaps that changes greatly between devices. Perhaps it should be by ... or is it by ....?
You need to know one important thing - by default everything you do without starting separate thread is executed on "main" thread (also knows as UI-thread).
If you do something, which can block - your UI will lag and users will suffer.
If you doing something, which is not about UI but about database query, network call or potentially long blocking operation - you need to start thread directly or use AsyncTask.
Also you must note, if you try to do something with UI (e.g. set value to a TextView) from not-main thread you will fail. UI can be acessed only from UI-Thread.