The title pretty much explains the issue.
I have a button that when I press toggles on/off this thread. It turns it on and off successfully... once, then it crashes if I try to turn it on again.
private Thread dataThread = new Thread(new Runnable(){
public void run() {
while(transmitPackets){
Log.d("Test","DERP");
}
}
});
and where its run...
toggleButton.setOnClickListener( new View.OnClickListener() {
public void onClick(View v){
transmitPackets = !transmitPackets;
if( transmitPackets ) {
toggleButton.setText("Pause");
dataThread.start();
}
else {
toggleButton.setText("Transmit");
}
}
});
transmitPackets is the boolean toggled by the button press. Named as such because this app will eventually be sending data over a network. The thread uses it to terminate as well.
The stack trace generated by the app crash isn't particularly helpful in figuring out how to fix it to me as it just says it crashed on restarting the thread--which was evident by the problem itself.
I'm new to the Android SDK and threading in Java both so I don't know where I could be going wrong. This seems to be the simplest implementation of a thread possible which is where I'm starting before I try to do anything funky with the thread.
It turns it on and off successfully... once, then it crashes if I try to turn it on again.
Indeed. You can't start a thread which has already finished. You'll need to create a new thread, and start that.
Note that the information that you can't restart a thread which has already been started should have been clear to you from:
The stack trace
The documentation:
Throws IllegalThreadStateException if the Thread has been started before
When something causes an exception, you should always read the exception message (and stack trace, as there may be causal information there) and documentation carefully.
Once thread is done, its gone. You can't restart. You may need to create new thread. Without stack trace, hard to suggest anything.
calling start() on thread doesn't mean you are restarting thread. That means you are starting new thread.
Issue could be something else. Post stack trace.
You would need to move your DataThread code into the setOnClickListener code, as you only create one thread, so when you 'start' it again, it can't, as it is done. You should declare DataThread where you do now, but set it in the listener
A better Implementation would be
private Thread dataThread = new Thread(new Runnable(){
public void run() {
while(true){
if(transmitPackets){
Log.d("Test","DERP");
transmitPackets = false;
}
}
}
});
that way the thread keeps going, and all you do is change truth value
of the transmitPackets value so it will run
Related
I have a simple app which updates the data in the background and while it updates, it disables all the other buttons and enables a TextArea to show the progress.
Steps:
Disable all the other buttons in the mainUI (Button name: plotButton)
Enable a TextArea showing that the updating has started (TextArea name: infoLogTextArea)
Then only start the update method (update() throws Exceptions).
Here is the code:
#FXML
public void handleUpdateButton() {
infoLogTextArea.setVisible(true);
infoLogTextArea.appendText("Please wait while downloading data from internet.....\n");
plotButton.setDisable(true);
updateButton.setDisable(true);
if(c!=null) {
Runnable task = new Runnable() {
#Override
public void run() {
// Thread.sleep(10000); -> sleep for 10secs
Platform.runLater(new Runnable() {
#Override
public void run() {
try {
c.updateData();
infoLogTextArea.appendText(c.getErrorLog().toString());
plotLabel.setText(c.getCityData().size()+" cities found and updated from internet");
infoLogTextArea.appendText("Successfully updated the data from Internet\n");
}catch (IOException e) {
infoLogTextArea.setText("Couldnot update the data from web: "+e.getMessage()+"\n");
}
finally {
plotButton.setDisable(false);
updateButton.setDisable(false);
}
}
});
}
};
new Thread(task).start();
}else {
System.out.println("c not initialized");
}
}
Now the code works well but sometimes steps 1 and 2 are not executed and it starts step 3 (updating) which can freeze the program.
If I put Thread.sleep(10 secs) in between step 2 and 3 then it works completely fine. (it is commented in the code)
But can anybody explain what is going on behind the scenes and why Platform.runLater() doesn't work all the time?
A JavaFX application runs on the Application thread, which handles all the UI elements. This means that if you click Button A and clicking that button starts method A that takes 5 seconds to complete, and then one second after clicking that button, you try to click Button B which starts method B, method B won't start until method A finishes. Or possibly Button B won't even work until method A finishes, I'm a little fuzzy on the detail there.
A good way to stop your application from freezing is to use Threads. To fix the above scenario, clicking Button A will start method A that starts a new Thread. Then the Thread can take as long as it wants to complete without locking up the UI and preventing you from clicking Button B.
Now, say something in method A needed to be on the application thread, for example, it updated a UI component, like a Label or a TextField. Then inside your Thread in Method A you would need to put the part that affects the UI into a Platform.runLater(), so that it will run on the Application Thread with the rest of the UI.
What this means for your example is that you have two options.
1. Don't use threads at all, since you don't want the user to be interacting with the UI while the updates are happening anyway.
2. move c.updateData() out of the Platform.runLater() like this:
Runnable task = new Runnable() {
#Override
public void run() {
c.updateData();
Platform.runLater(new Runnable() {
#Override
public void run() {
try {
infoLogTextArea.appendText(c.getErrorLog().toString());
plotLabel.setText(c.getCityData().size()+" cities found and updated from internet");
infoLogTextArea.appendText("Successfully updated the data from Internet\n");
}catch (IOException e) {
infoLogTextArea.setText("Couldnot update the data from web: "+e.getMessage()+"\n");
}
finally {
plotButton.setDisable(false);
updateButton.setDisable(false);
}
}
});
}
};
Either one of those will work, but what you're doing right now is you're on the application thread, and then you start another thread whose only purpose is to run something on the application thread.
The documentation of the Platform class explain everything very well :
public static void runLater(Runnable runnable)
Run the specified Runnable on the JavaFX Application Thread at some
unspecified time in the future. This method, which may be called from
any thread, will post the Runnable to an event queue and then return
immediately to the caller. The Runnables are executed in the order
they are posted. A runnable passed into the runLater method will be
executed before any Runnable passed into a subsequent call to
runLater. If this method is called after the JavaFX runtime has been
shutdown, the call will be ignored: the Runnable will not be executed
and no exception will be thrown. NOTE: applications should avoid
flooding JavaFX with too many pending Runnables. Otherwise, the
application may become unresponsive. Applications are encouraged to
batch up multiple operations into fewer runLater calls. Additionally,
long-running operations should be done on a background thread where
possible, freeing up the JavaFX Application Thread for GUI operations.
This method must not be called before the FX runtime has been
initialized. For standard JavaFX applications that extend Application,
and use either the Java launcher or one of the launch methods in the
Application class to launch the application, the FX runtime is
initialized by the launcher before the Application class is loaded.
So use the runLater to only update any UI elements on a non JavaFX thread and leave any heavy job to sit on the background thread.
I am developing a Bluetooth application.In that I have 1 button, on click of the button I am starting a thread.Inside the thread, I am discovering and connecting ble devices.Repeated click of the button causing the UI to hang.
Code I am using to create the thread is:
new Thread(new Runnable() {
#Override
public void run() {
//do bluetooth stuffs
}
}).start();
I am not stopping this thread anywhere.
I don't know what is causing the UI to hang please help me.
Do you mean that if you keep smashing the button repeatedly (without waiting for the task to finish), then the ui lags? Or when you press the button, wait a bit, then press again.
If it's the first case (where you're mashing the button in quick succession), try this: If you set some boolean flag when you first start the process, then each time you press the button check if that flag is set to true, and only execute the search if the flag is false. Not sure if this is your issue but it's worth a shot?
For the Android, you can use handler instead thread or handle your thread using handler is a better way, for example, you can use like
new Handler().post(new Runnable() {
#Override
public void run() {
}
});
if you want to use the main thread then use like.
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
}
});
for information, you can refer this link
difference between Thread and Handler
I would advise you to use a thread pool instead. Resources are limited.I didn't understand why are you creating a new thread for every button press. a bunch of threads banging for a resource might freeze Your app, or there could be implementation related issues like a deadlock, thread contention, or thread starvation which will definately prompts to freeze your application.
My application has one service which runs until user pressed exit button. I know giving exit button in android is not good design but in my application it is desired.
In my application I also have a thread to send Http request, download a file and then parse it in background so that UI will not block. In my thread's run method there are sequential steps (like download a file, then parse it), there is no while or for loop in it.
When user presses exit button, is there any way to stop the background thread if it is running without kill process (using Process.kiil(pid) or System.exit(0)) ?
I have tried AsyncTask also. Whatever in run method of thread, i put it in doInBackground method. When user presses exit button i have canceled asynctask. Cancelling task not stop the background thread completely because after file download it will go in parser to parse the file (i.e. parsing is done in background thread but it at the time of parsing it is not in doInBackground or run method. It will in parsing method of parser class or in Default handler class for parsing.)
From googling I read many blogs and other stackoverflow questions about thread but still I cannot find any solution for it.
Please help....thanks in advance..
before each step you could add a line like
if(stillRunning){
//next step
}
and when you want it to stop, you just set stillRunning to false.
(1) use this to stop application instead of exit
finish();
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addCategory(Intent.CATEGORY_HOME);
startActivity(intent);
(2) use new Thread instead of asynk task which you can stop by calling stop method
Thread myThread = new Thread ()
{
public void run()
{
Looper.prepare();
doMyWork();
}
}.start();
and call stop on myThread
Probably, your connection and parser use same InputStream. If you quit, try to close the stream and a connection. In that case, some kind of Exception will be thrown and background thread will finish job with error but very fast. If you are in the middle of file saving, you must check every write(buffer) if you are canceled or try to close FileOutputStream.
Stop thread at instance (when exit event occurred from UI) is not possible without using
Process.killProcess(Process.myPid());
I am using the Javamail API connecting to my IMAP server. Everything is working great with the javax.mail.Folder.idle() method. My listener gets called when a new mail comes in. However the problem is idle blocks forever, how do I interrupt it? How do I actually stop the listening without killing my Java program?
I've tried calling Thread.interrupt() on the idle'd thread. Nothing happens. I am running out of ideas.
Performing any operation on that folder (from another thread) will cause idle() method to return immediately. So if you want to forcefully interrupt it, just call close() from a new thread.
If you read the documentation properly, and read the source code, you'll realise that you have to create a new thread for calling .idle().
Allocate that thread to a variable, and whenever you want call the interrupt() on that thread, or just ignore notifications!
If you need to get idle() going again, just rerun the thread!
I created something similar, so you might wanna check it out.
https://github.com/mofirouz/JavaPushMail/blob/master/src/main/java/com/mofirouz/javapushmail/JavaPushMailAccount.java
Good luck
A proper way to abort IDLE command is the following snippet. Note that the Folder instance should be the same as the one used to start idling. I've tested the other solutions proposed on this thread but they didn't work in my case.
IMAPFolder folder = store.getFolder("INBOX");
try {
folder.doOptionalCommand("Abort IDLE error mesage", new IMAPFolder.ProtocolCommand() {
#Override
public Object doCommand(IMAPProtocol p) throws ProtocolException {
p.idleAbort();
return Boolean.TRUE;
}
});
} catch (MessagingException e) {
e.printStackTrace();
}
In a java application,when the user hits download,establishing the remote connection and downloading the content from remote is done in a separate thread and a dialog is popped up in the screen to show the download progress. Now a cancel command has been added to the dialog inorder to provide the user with an option of cancelling the download. When the user hits cancel button, dialog can be disposed using dispose() method from the program but how can I stop/kill the thread which has already been initiated? Thread does the following task: 1.Establishes connection with remote 2.Downloads content from remote 3.stores the content locally (content is transferred via streaming)
Please help me to resolve this issue
Stopping a thread is probably the wrong way to look at. The actual resource consumed by a single thread on a desktop machine is irrelevant. Think of it as aborting the download.
If the read is blocking, then that isn't really much of a problem. You can wait until there is some data before not reading again. A more abrupt approach would be to call close on the stream (from another thread).
You need to check for a stop flag somewhere in your download routine.
public DownloadThread implements Runnable {
private boolean stop;
public void stop() { stop = true; }
public void run() {
while (!stop) {
// download a block, save it somewhere
}
}
}
Of course this lacks the necessary synchronization but that’s about how you stop a thread without using the deprecated Thread.stop().
Firstly, the stop() operation on java.util.Thread is deprecated, and its use is strongly discouraged, since it can leave things in an unstable state. It's much preferred that you send a message to the Thread's Runnable asking it to stop itself safely.
The problem you have is that your thread is doing blocking I/O operations, and so it won't receive your message until the I/O is complete.
The best you can hope for, unless someone else comes up with a better option, is to interrupt() the Thread, and hope that the I/O classes notice and stop the download.
Edit: The javadoc for Thread.interrupt() does say that I/IO can be interrupted if you use java.nio, but it's very unlikely that you are. "Normal" java.io traffic is blocking, and cannot be interrupted.
Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?
I suggest you do what Bombe suggested (with a volatile variable) and just leave the thread to die in the background, returning control back to the user. It might spend a little while fetching the last block, but if the user can carry on doing something else it doesn't matter too much. If your block sizes were relatively small the wasted bandwidth wont be too much, and the IO stuff will timeout eventually and return if the connection has gone bad.
public class Downloader {
protected final AtomicBoolean run = new AtomicBoolean(false);
protected final byte[] file;
protected volatile double progress = 0.0;
public download(URL url) {
run.set(true);
new Thread() {
#Override
public run() {
final ByteBuffer buffer = new ByteBuffer();
while(run) {
/* download chunk, e.g add to buffer, or whatever */
buffer.put(chunk);
progress = buffer.size().size() / fileTotalSize; //e.g
}
syncrhonized(Downloader.this) {
file = buffer.array();
}
}
}.start();
}
public void abort() {
run.set(false);
}
public double getProgress() {
return progress;
}
public synchronized byte[] getFile() {
return file;
}
}