Threads freezing screen - java

All this is in the same class and onCreate method:
String arrayExtra[] = {"1"};
for(int x = 0; x < arrayExtra.length; x++){
Thread thread = new Thread(new Runnable(){
#Override
public void run(){
try{
final EditText etAbun = (EditText) findViewById(R.id.etIsoAbunNum);
synchronized(this){
wait();
allExtraiso.add(etAbun.getText().toString());
}
}catch(Exception e){
e.printStackTrace();
}
}
});
Thread thread2 = new Thread(new Runnable(){
#Override
public void run(){
try{
synchronized(this){
Thread.sleep(1000);
final Button bNext = (Button) findViewById(R.id.bIsoAbunSave);
bNext.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View arg0){
notify();
}
});
}
}catch(Exception e){
e.printStackTrace();
}
}
});
thread.start();
thread2.start();
try{
thread.join();
}catch(InterruptedException e){
e.printStackTrace();
}
try{
thread2.join();
}catch(InterruptedException e){
e.printStackTrace();
}
}
What this code should do, is create 2 threads, wait for a button click, then when the button is clicked, do notify(), then continue the remaining code. What this does is though is just freeze the screen. The for loop should not be running forever, but I am not sure.

You are starting the separate threads and the call join() on them right away. The call join() is executed by your main thread (since you are in onCreate). What this method does is tell your current thread to wait until the other thread is finished. So your main thread gets blocked until the other thread dies.
But your threads are waiting for the user to click a button. User events are processed by the UI thread, which is currently blocked in join(). So the click is not processed, the event handler will never be called and you have a deadlock situation.
Multi-threading should be avoided whenever possible, because it adds a lot of complexity to your program and often does not add any benefits. It is necessary when doing something time consuming in android and you don't want to block the UI thread with that task.
You should probably remove the threads and find some other way to achieve what you want.
Update
There is actually another problem with your code, that would also prevent it from working: you are synchronizing, waiting and notifying on different objects. So the call to notify() would never reach the thread in wait() even if the click event was processed.

You seem to be doing the major part of your work inside the Main Thread (UI thread) I don't think you want to use join here. A reentrant Lock with a Condition object is probably what your are looking for if you want to keep this mechanic. with this you will be able to await inside you thread Object when you want to block and signal when the button is pushed.
http://developer.android.com/reference/java/util/concurrent/locks/ReentrantLock.html
but unless you wanted to do processing before the button was pushed, creating the thread lazily upon the action occurring might be a good approach. AsyncTask might also be very good to look at.

Related

why i can't do anything in my application when Jbutton is pressed and performing its defined function in java?

this is how I'm trying to accomplish this:
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("Hello there");
Thread.sleep(1000);
panel.updateUI();
}
});
I set Enter button as the default button so when I keep pressing it the button press maybe 100 times or more but because I'm using Thread.sleep(1000) it takes some time so I have time to type in my JtextField or even close the window but can't do anything.
also, I tried to put btnNewButton.addActionListener() in the run method of a thread but no difference.
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("Hello there");
Thread.sleep(1000);
panel.updateUI();
}
});
}
});
thread.start();
// I used try catch block in real code
can anyone help me to solve the issue?
**I'm creating this application in eclipse using windowsBuilder.
This is because of something that is called EDT - the Event Dispatch Thread.
This special purpose thread is responsible for all the events in your GUI - including drawing (refreshing) and interactions (button click). This means, that exactly the same thread is used to draw your application as the one that is used to execute actionPerformed code. Since you are literally halting that thread for some amount of time, your application will be non responsive for that exact period of time.
Whatever is being executed on user interactions should be short and execute fast for the reason of not blocking the application. If you need to do some heavy stuff, there is a facility for that purpose called SwingWorker that allows you to easily do some processing in the background thread (pool) and schedule UI updates during execution (like update of progress bar)
In your second "thread" snippet, your thread is not doing anything beside adding actionListener to the button, and then it terminates (probably after less than 1ms ;)) - action callback is still executed by the EDT. If you would start that custom thread from inside of run method - then it would be indeed in parallel and GUI would not be frozen - but again, SwingWorker is the way to go here.
Not entirely sure what your code is supposed to do, but if you want to press the button and then 1000ms later it will check your field you should do something like this:
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
System.out.println("before 1000ms");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("after 1000ms");
System.out.println("Reading the text field ...");
}
});
thread.start();
System.out.println("after the thread");
Output:
after the thread
before 1000ms
after 1000ms
Reading the text field ...

Swing Window Listener Threading Issue

I have a Window Listener on the main JFrame of my application. I also have a button listener on a button within the application. I used this as the pattern for the button listener:
good.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
// We're going to do something that takes a long time, so we
// spin off a thread and update the display when we're done.
Thread worker = new Thread() {
public void run() {
// Report the result using invokeLater().
SwingUtilities.invokeLater(new Runnable() {
public void run() {
for(int i=0; i<1000000; i++){
System.out.println("foo");
}
}
});
}
};
worker.start(); // So we don't hold up the dispatch thread.
}
});
When I click on the button, I see the printout for each iteration, but the window listener is not triggered until after the loop has finished executing. The print 'foo' is just there to simulate something that takes a while, and I want the listener to be triggered as soon as the window event occurs (which could be somewhere in the middle of the run() method execution), but it seems like it's not being triggered until the end of the for loop.
Any idea why?
Swing is single-threaded - the Event Dispatch Thread (EDT) manages painting and events for Swing. Any long running tasks placed on the EDT will prevent the EDT from doings tasks until the long running task is complete (in other words, the UI will seem like it has locked up). Here, your code dispatches the long running process (the for loop) onto the EDT using SwingUtilities - if you have a long running task and want a responsive Swing UI during the process, then place your long running task into it's own Thread, or use a SwingWorker.
So, all this...
// Report the result using invokeLater().
SwingUtilities.invokeLater(new Runnable() {
public void run() {
for(int i=0; i<1000000; i++){
System.out.println("foo");
}
}
});
Will do is, is cause the loop to be executed within the context of the Event Dispatching Thread, which will prevent the EDT from processing the event queue, including paint request.
In your case, it might be easier to use a SwingWorker which you can use to publish/process information from the background thread to the EDT as well as supports progress notification
See How to use SwingWorker for more details

Getting and Setting a Flag variable in a thread

I am interfacing with a JNI that allows me to use a fingerprint scanner. The code I have written takes the scanned ByteBuffer parsed back to it by the JNI and turns it into a BufferedImage for saving.
What I can't figure out is how to wait for the scan thread to finish before the the jlabel icon on my GUI tries to update. What would be the easiest way to do this?
What else do I need to add?
Edit:
//Scanner class
Thread thread = new Thread() {
public void run() {
// [...] get ByteBuffer and Create Image code
try {
File out = new File("C:\\Users\\Desktop\\print.png");
ImageIO.write(padded, "png", out);
// [???] set flag here
} catch (IOException e) {
e.printStackTrace();
}
}
};
thread.start();
return true;
//Gui class
private void btnScanPrintActionPerformed(java.awt.event.ActionEvent evt) {
Scanner scanPrint = new Scanner();
boolean x = scanPrint.initDevice();
//Wait for the scanning thread to finish the Update the jLabel here to show
//the fingerprint
}
Not sure if you are using Swing or Android for UI but you would want to notify the main event dispatch thread (in swing it is called just that). You would run the scanning thread, then when complete send a 'message' to the EDT with the action that you want to be done to the button.
Thread thread = new Thread(new Runnable(){
public void run(){
//scan
SwingUtiltilies.invokeLater(new Runnable(){
//here you can update the the jlabel icon
public void run(){
jlabel.setText("Completed");
}
});
}
});
In UI development there is no waiting for an action to complete because you always want the EDT to be responsive.
at the end of a the scan thread, use SwingUtilities.invokeLater() to update the gui with the results of the scan.

java: stop thread on ESC

I am writing a simple game in Java, and I have a following issue:
I have a controlling class, called MainGameFrame, in which there is initialized gameThread. MainGameFrame has a key listener for Esc key, so that it pauses/resumes gameThread. However, this doesn't work:
public void keyPressed(KeyEvent e) {
// pause the game
synchronized(gameThread) {
if(e.getKeyCode() == e.VK_ESCAPE) {
try {
if(gameThread.getState() == Thread.State.WAITING) {
System.out.println("continue");
gameThread.notify();
System.out.println("after continue");
} else {
System.out.println("pause");
gameThread.wait();
System.out.println("after pause");
}
} catch (InterruptedException ex) {
Logger.getLogger(MainGameFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
It will pause on Esc and output "pause", but not "after pause".
gameThread.wait() doesn't make the gameThread thread to pause. It makes the current thread (i.e. the event dispatch thread) to wait. Since the EDT is waiting, it can't receive a keypressed event anymore: the entire GUI freezes
Read the Java tutorial on concurrency, and particularly the following page: http://download.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
You should probably change the value of an AtomicBoolean variable, which is regularly inspected by the game thread to know if it has to pause. The game thread would then wait on a shared lock object. When resuming, change the boolean variable again and notify the game thread.
It waits until another thread calls notify(). Your not doing that, so "after pause" is never printed.
What do you want to achieve with gameThread.wait()?
You have the idea of wait and notify backwards.
One thread can not directly pause, or kill another thread. You can, however, change a variable that is shared between threads. When the interested thread sees that the variable has changed it may "pause" itself.
private static volatile boolean paused = false;
private static ReentrantLock pauseLock = new ReentrantLock();
private static Condition unpaused = pauseLock.newCondition();
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
if (!paused)
paused = true;
else {
pauseLock.lock();
try {
paused = false;
unpaused.signal();
} finally {
pauseLock.unlock();
}
}
}
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(200,200));
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
Thread gameThread = new Thread() {
public void run() {
while (true) {
System.out.println("running");
// presumably the game rendering loop
if (paused) {
pauseLock.lock();
try {
try {
unpaused.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
pauseLock.unlock();
}
}
}
}
};
gameThread.start();
}
I would also avoid using wait and notify directly as there are some caveats you must be aware of when using wait & notify (such as your thread that is waiting actually has to wait inside a loop because it can be woken up without notify ever being called).
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4308396
You should also be sure to always acquire and release locks in the following pattern, if not using synchronized blocks:
l.lock();
try {
// code
} finally {
l.unlock();
}
http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Lock.html
I'd also recommend reading:
http://www.javaconcurrencyinpractice.com/
There are more pitfalls than you would think when doing concurrent programming in Java.
The reason that one can not pause or kill a thread from another thread is that the thread doing the pausing or killing has no idea where in execution the other thread is and what resources the other thread might hold.
What would happen if Thread A paused Thread B and Thread B happened to hold several resources that Thread A will need later? What happens if Thread A kills Thread B while Thread B is using a resource that it is supposed to do some special clean up on?

Slowing the GUI down in Android

My Android App works fine, except the end sequence. Its a game and at the end the screen shows the score:
TextView allscores = new TextView(this);
allscores.setText("Your score: "+ mypoints);
Next I want the GUI to slowdown for a few seconds so the user has time to take in the information. Maybe 2 or 3 secs is fine.
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
layout.removeAllViews();
Bear in mind, I'm new to thread programming. All this is done on the UI thread, I have no other threads running.
Next I put in a final splash screen ending:
AnView animator = new AnView(this);
layout.addView(animator);
where AnView is my own extension of View.
All in all it runs great. Problem is the thread sleeps for 3 seconds without showing my final score. I don't know why. I don't know why it doesn't show my final score before sleeping. It actually goes blank, indicating that it removed all views and then slept.
You're not seeing the score because sleeping on the UI thread prevents the layout and drawing operations that make your text changes visible. Never sleep on the UI thread.
Using a new thread for this is overkill. Use a Handler and the postDelayed method to make something happen after a delay.
private final Handler mHandler = new Handler();
Then when you want to do something later,
mHandler.postDelayed(new Runnable() {
public void run() {
doDelayedThing();
}
}, 3000);
As others have pointed out: don't use sleep in the UI thread.
What you should do instead is described here:
http://developer.android.com/guide/appendix/faq/commontasks.html#threading
in section "Handling Expensive Operations in the UI Thread"
It is not recommended to ever sleep the main UI thread. Try something like this:
new Thread(new Runnable(){
//do work here
});
Or you could try using a Toast popup for the score.
You can also use Timer to wait 3 seconds, which will start a new thread after the time runs out.
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
AnView animator = new AnView(this);
layout.addView(animator);
}
}, 3000);

Categories

Resources