Calling thread repeatedly causing Ui hang in android - java

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.

Related

Why is Thread.sleep() not pausing my code? [duplicate]

For my new Android application I need a function, that timeout my application for 3 Seconds. I tried the function "sleep()" like this:
seekBar1.setProgress(50); // Set something for my SeekBar
try{
Thread.sleep(3000); // Wait for 3 Seconds
} catch (Exception e){
System.out.println("Error: "+e); // Catch the exception
}
button.setEnabled(true); // Enable my button
It seems to work, but if I was running the application it does it like this: Wait for 3 Seconds, set progress and enable button. I want first to set the progress and then wait for 3 seconds and only then to enable the button.
Is "sleep()" for the right for my use or what can I do else that my application does it in the right order?
You can use postDelayed() method like this:
handler=new Handler();
Runnable r=new Runnable() {
public void run() {
//what ever you do here will be done after 3 seconds delay.
}
};
handler.postDelayed(r, 3000);
You shouldn't ever block the ui thread with a sleep. Its ok to sleep on another thread, but even then it should be avoided. The right way to do this is to post a Runnable to a Handler. Then put whatever code you want to run after the delay in the run() method of the Runnable.
You can define a Handle in your Activity and use Handle.postDelayed() from Activity's onCreate()so you receive a message on that handle in 3 seconds. Upon receving you can enable the button.
You can do the same using AsyncTask where in doInBackground() you just sleep for 3 sec. Then in onPostExecute() you enable the button.
Use object of Handler class and use method handler.postDelayed(thread,time).Don't use sleep() it will block ui thread.

How does Platform.runLater() function?

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.

How to wake thread by condition

I have an activity running, of course, on UI thread and there is another thread running in background and communicating with activity using Handler post method(through looper).
When screen is turned of or application is hidden it continues to work.
So I need to stop this thread in onPause method and wake it up in onResume mehtod.
In my thread I have condition to pause it or to stop.
How to can I put thread to sleep in onPause method. And wake it up after activity is again in foreground.
I can do it with one object using monitor calling wait method and than notify on this object.
But is it good approach ? Or there is another way to do this elegantly.
Sounds like a good place to use a turnstile. Initialize a Semaphore with one permit:
Semaphore turnstile = new Semaphore(1);
Make your background activity periodically pass through the turnstile like so:
turnstile.acquire();
turnstile.release();
When the foreground thread wants the background thread to pause at the turnstile, it can lock the turnstile:
turnstile.acquire();
And when the foreground thread wants that background thread to start working again, it can unlock the turnstile():
turnstile.release();
Good software engineering practice would be to wrap the whole thing up in a Turnstile class with appropriately named methods for the foreground and background threads to call. I'll leave that as an exercise for the reader.
Android suggests using services for long term background tasks, but if you're just opening a new thread that is tied to your Android lifecycle, I don't think it would be bad to use a monitor and call wait/notify. Can you be more specific with what you are doing?
This is an overview of how I would stop and resume a stopped thread. (You may want to implement runnable in yours)
class ThreadDemo extends Thread {
private Object monitor; //This is the monitor
private boolean keepRunning = true;
private Thread t;
ThreadDemo(){
System.out.println("Creating thread");
}
public void callinOnResume(){
synchronized(monitor){
monitor.notify();
}
}
public void callinOnPause(){
try {
synchronized(monitor){
System.out.println(threadName + "Waiting");
monitor.wait();
}
} catch (InterruptedException e) {
System.out.println("Thread interrupted " + e.toString());
}
}
public void run() {
System.out.println("Starting to loop.");
while (keepRunning) {
//stuff
}
System.out.println("Done looping.");
}
public void start ()
{
System.out.println("Starting " + threadName );
if (t == null)
{
t = new Thread (this, threadName);
t.start ();
}
}
}
It is a bad practice to stop/resume a thread outside that thread. The thread must decide itself when to run and when to stop. As a result, the background thread should check periodically if its work is still needed, and the client (foreground) thread should issue some signals about that.
One way to issue signals is to form that signals as jobs of type Runnable and then execute them on a thread pool. So when the activity sleeps, it just does not issue signals.
The main problem when a background thread wants to update the UI is that the target Activity can be closed (or in the process of recreation) and the updating task fails. The AcyncTask class does not solve this problem. A correct solution is published at my Github workspace. But before to use this or another solution, think twice if you really need a background thread. The best way is not to use background thread at all, making all UI updates directly on the UI thread. Of course, if updates are taken from the network, then a background thread must be used.

How to show progress in a job in eclipse rcp?

I update the gui of my eclipse rcp application with asyncExec() in the run()-method of a job.
Job job = new Job("The Job") {
#Override
protected IStatus run(IProgressMonitor monitor) {
try {
monitor.beginTask("", IProgressMonitor.UNKNOWN);
Display.getDefault().asyncExec(new Runnable() {
#Override
public void run() {
\\update gui
}
});
...
PlatformUI.getWorkbench().getProgressService().showInDialog(Display.getCurrent().getActiveShell(), job);
job.schedule();
I am trying to show the user some indication of how long it is going to take with a progress monitor and the showInDialog method but i would also like to have a busy cursor in the first few moments before the dialog appears. How does it work in this case with the BusyIndicator? I also have the problem that i can't cancel or exit the progress dialog (cancel button and exit button don't show any effect).
Job is not suitable for passing to the progress service like this.
You should just call job.schedule() and let it run. If you call
job.setUser(true);
before scheduling the job it will display a progress dialog of its own after a few seconds.
Your job should call monitor.worked(1) regularly to update the progress monitor. The job should call monitor.isCanceled() to check for the cancel button.
If your job is mostly doing GUI work then use UIJob to run the whole job in the UI thread (but this is more likely to slow down the UI).

Restarting a Finished Thread Causes Crash (Android SDK)

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

Categories