android: Running a time consuming task in UI Thread? - java

in my app i am trying to process a task in the UI Thread when a button is clicked (the task is executed only once when the button is clicked)... since the task is time consuming my UI gets frozen and doesn't allow the user for further input...
my question is that is there any other method apart from "Thread"s to run my task so that my UI doesn't get frozen ..since i don't want the task to run repeatedly..
if possible can u provide me with sample code or links....
thanks :)

AsyncTask is a very convenient way for that, it has great hooks for initialization and clean-up.
Docs including example here.

Related

Is it possible to interrupt a runnable called by ApplicationManager.getApplication().executeOnPooledThread?

I am currently working on developing an IDEA extension that embeds JCEF for frontend interaction. Once the user clicks on a button, the implemented onQuery method in MessageRouterHandler would be executed, and a time-consuming task would be performed.
The time-consuming task is implemented in a method (asynchronous on a thread other than the main thread in case the UI to be frozen) and is wrapped in a form like
private void task(CefBrowser browser, CefQueryCallback callback) {
ApplicationManager.getApplication().executeOnPooledThread(() -> {
...DETAILED IMPLEMENTATION FOR THE TASK...
});
}
The runnable only contains the operation related to file reading (selected by the user clicking on another button on the JCEF webview) and has nothing to do with the IDE interface so I did not add runWriteAction or runReadAction here.
Since the task might take a longer time, I would like to add a button for the user's cancelling order. However, I am quite new to extension development, and could anyone help me to figure out how to implement the cancel function? Great great many thanks for any suggestions.
A time consuming task should be performed under a progress indicator, see com.intellij.openapi.progress.ProgressManager. During the task you can then call com.intellij.openapi.progress.ProgressManager#checkCanceled to see if the task has been canceled by the user. This call is supposed to be cheap, so you can call it often to make sure your process responds promptly to the users' request for cancellation.

i'm so confused about Threads

I read a lot about threads but don't understand yet :( let me explain to you what I have learned about threads. all we are working on such as codes any thing worked on UI thread or Main thread right? After that what happens if we call runOnUiThread? and my other question how do we know it's Time to use a new thread? I mean how do we understand we are working on another thread or replace or code in the new thread?
I know this is an unclear question but I don't understand as well. Please help me Thanks, john.
Let me try to answer. Actually Android has Main Thread (also called as UI Thread) and other thread.
Main Thread is basically for showing UI and other thread is for processing other big processes such as connecting to the server, etc.
runOnUiThread is called when you want to move from other thread to main thread. It is needed since only main thread can show/display result on UI. So when you have done some process on other thread, and you want to display the result on the apps, you need to show it on main thread by calling runOnUiThread.
We working on other thread only if it is a big or lengthy process like taking data from the server, load data, etc. And we move from other thread to main thread whenever we want to show some UI result.
Easiest way is to use AsyncTask<> class. You'll need to override three functions.
doInBackGround(...) : The codes that gets executed in background thread.
onPreExecute(..) : code that gets executed before background thread
completes executing like displaying progress bars, etc.
onPostExecute(...): Code that gets executed after background thread
has completed running. Perform task like updating UI in here
One general rule of thumb is: Don't use multithreading if you don't need to. Multithreading is always error-prone, and in many situations there's no benefit. Basically, you start a new thread whenever you execute a lengthy operation (i.e. some extensive computation like image processing) that would block the main thread for some time, so the application would become unresponsive.

Correct design to prevent blackscreen issue in JFrame

In my application I have a main frame window GUI, that launches a task in an executor service.
The submitted task generates output and stores in a file on Disk.
As soon as the o/p is generated GUI (observer) is informed of the o/p generated.
Here the problem is I am keeping a wait loop inside the main frame and as soon as a notification is received, the main panel is repainted on the main frame.
For small tasks this works fine, but as the size of the threaded task increases. The wait loop time increases and the GUI main window turns black till computations are done.
Can you please help me in correcting the design. Also How can a SwingWorker thread help in this case.
The wait loop time increases and the GUI main window turns black till computations are done.
Then you long running task is executing on the Event Dispatch Thread (EDT) which prevents the GUI from repainting itself. You need to execute the long running task in a separate Thread. A SwingWorker is a separate Thread which has an API that also allows you to execute code on the EDT as required, for example when the code finishes executing or when you have intermediate results.
Read the section from the Swing tutorial on Concurrency for more information. You can always search the forums for example of using a SwingWorker.
1)
Wait loops are the bane of all that is GUI. They are OK in other threads you have spawned, tricky in Executors (as they sometimes have limits on number of Threads, depending on which you use), and are completely out of the question on the EDT. That is the reason for your "blackscreen"
2)
Instead of using a custom (I assume it's custom) signal protocol and a wait loop, you could use one of the utility classes in Swing. For example, SwingUtilities has a couple of nice methods - invokeLater and invokeAndWait that take a Runnable and execute it on the EDT as soon as they can. Using this instead of the signal you have will allow you to not block the EDT and make your GUI responsive.
3)
If you really want to use a SwingWorkeryou may want to look through the documentation for it. It is essentially a way to do background tasks and report progress or completion/result to the EDT. Currently it uses an ExecutorService with 2 background threads, so having a lot of long running tasks on them is not a good idea (they will block each other). When creating a SwingWorker you would specify the method to be ran in the background, the method to be ran on the EDT when intermediate results are available, and the method to be ran on the EDT when you're finished either successfully or in error.
4)
This does not pertain to the question at hand, but if you ever get into a situation where you need a wait loop in the EDT and cannot avoid it using another design or technique, you can always switch to using a Timer. It can be setup to be called every x milliseconds without blocking the EDT and turned off once you are satisfied with some condition.

Creating another AsyncTask inside of doInBackground

I recently looked through SO to find the answer to the same question here, but there was not an answer directed at the question in regards to the risk of doing so. But basically I want to run another AsyncTask inside the doInBackground() method of another AsyncTask. Is this a bad approach and/or does it leave any potential side effects?
I know that running it in the onPostExecute() works and so far from past experiences I have not had any issues due to the fact that onPostExecute() runs back on the main thread which started a AsyncTask to begin with.
From the API docs:
•The task instance must be created on the UI thread.
doInBackground() runs on the background thread. So you cannot create and run another asynctask from doInBackground().
http://developer.android.com/reference/android/os/AsyncTask. Have a look at the topic under threading rules.
When an asynchronous task is executed, the task goes through 4 steps: (Straight from the doc)
1.onPreExecute(), invoked on the UI thread before the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.
2.doInBackground(Params...), invoked on the background thread immediately after onPreExecute() finishes executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. This step can also use publishProgress(Progress...) to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress...) step.
3.onProgressUpdate(Progress...), invoked on the UI thread after a call to publishProgress(Progress...). The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.
4.onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.
When first introduced, AsyncTasks were executed serially on a single background thread. Starting with DONUT, this was changed to a pool of threads allowing multiple tasks to operate in parallel. Starting with HONEYCOMB, tasks are executed on a single thread to avoid common application errors caused by parallel execution.
If you truly want parallel execution, you can invoke executeOnExecutor(java.util.concurrent.Executor, Object[]) with THREAD_POOL_EXECUTOR.
Also you can consider using an alternative RoboSpice.https://github.com/octo-online/robospice.
Can make multiple spice request. Notitifes on the ui thread when task is complete. Worth having a look at robospice.
AsyncTask(), with the exception of the Honeycomb releases, execute serially. So, no, you cannot execute another AsyncTask() from within doInBackground() -- I guess I should say that I've never tried it, but it's highly unlikely you're going to achieve the desired affect.
I asked about AsyncTask() execution during one of the Google Office Hours. Straight from their mouths when asked, "Why did it change from serial to parallel and back to serial execution?"; "Because it broke a lot of stuff."

Threading with Java Swing

I have a swing worker which configures a serial port connection. This process takes an indeterminable time to complete, sometimes 1 minute sometimes a lot more.
My problem arises when users click a button that needs configuration data whilst the worker thread is still configuring.
I would like to know how to execute a user's request only if the worker thread has completed. Else if worker thread in still alive, I want execution to wait until worker thread has finished.
add PropertyChangeListener to SwingWorker, then you can to determine of status from SwingWorker
have to implemented get() in the SwingWorker's method done(), otherwise isn't possible to get an exeption(s) from invoked methods
depend of code but I doubt that is possible to change setting, untill current thread ended, better could be to SwingWorker#cancel() and then to restart this instance
You could check in your buttons ActionEvent if task.isDone() - where task is your SwingWorker - and continue only if it is true. But you might want to show a popup or something, otherwise the user might get confused why nothing is happening.
Another simple solution is to expose the button and disable it while the task is running and enable it again when it's finished. Then the user can't click the button until it's ready.

Categories