I want to do something very simple. I have a progress-bar and a textView that I want to dynamically update on a button click, but more than once during the function call.
I want it to change to 'A' then wait a second, then switch to 'B' ... for example.
I understand that my function blocks the UI/main thread, which is what if I setText() ten times, I only see the tenth text appear when the function completes.
So I've tried handlers/runnables in the UI thread, invalidating (and postInvalidating) to encourage refreshing and runOnUiThread() and they all just update when they've finished running leaving me only with the final state.
public void requestPoint(View v) {
textProgress.setText("Requesting A Point");
waiting(200);
progressBar.setProgress(5);
textProgress.setText("Request Received!");
waiting(500);
....
}
I think I've turned nearly all the similar question links purple and wasted way too much time on this simple thing (although I did learn a lot about threading on Android) but I feel I must be missing something crucial, this doesn't seem like that hard of task.
Any help would be greatly appreciated.
Assuming you really do just want to waste time with your waiting method. This is assuming a 200ms delay followed by a 500ms delay like in your example.
public void requestPoint(View v) {
textProgress.setText("Requesting A Point");
handler.postDelayed(new Runnable(){
public void run(){
progressBar.setProgress(5);
textProgress.setText("Request Received!");
}
}, 200);
handler.postDelayed(new Runnable(){
public void run(){
....
}
}, 700);
....
}
Related
I'm new to JAVA and trying to learn some concurrency concepts.
I have a simple GUI class that pops-up a window with 1 button which I want to use for pause/continue.
Also, I have a class that extends TimerTask, it looks like below and start with the GUI:
public class process extends TimerTask {
public void run() {
while(true) { /*some repetitive macro commands.. */ }
}
}
Real question is, how can I pause the task onClick of the button and also continue onClick of the button if already paused?
I have taken a step to use a boolean to flag the button as it changes from pause to continue on each click.
But then I had to type a lot of while(button); for busy waiting inside the while()...
Do you think I can make like Thread.sleep() or something but from outside the task thread?
OLD ANSWER
Basically, there is no support for pause and resume on TimerTask, you can only cancel, check here
perhaps you might want to read about threading as that's the alternative I know of that has an interrupt and start features and then you can keep track of the progress of what you're doing to resume where it stopped.
So, I will suggest you go through this link, because you need to understand threading not just copy a code to use, there is a sample code there that will definitely solve your problem also.
Note that running an endless while loop will basically cause your program not to respond, unless the system crashes. At a certain point, the data becomes an overload and the program will overflow. This means it will fail.
.
NEW ANSWER
So, response to the new question, I was able to run a tiny little program to demonstrate how you can achieve something that looks like multithreading when working with SWING.
To rephrase your question: You want to run an indefinite task like let say we're playing a song, and then onclick of a button to pause the song, on click again should continue the song?, if so, I think below tiny program might work for you.
public class Test{
static JLabel label;
static int i = 0;
static JButton action;
static boolean x = false; //setting our x to false initialy
public static void main(String[] args) {
JFrame f=new JFrame();//creating instance of JFrame
label = new JLabel("0 Sec"); //initialized with a text
label.setBounds(130,200,100, 40);//x axis, y axis, width, height
action=new JButton("Play");//initialized with a text
action.setBounds(130,100,100, 40);//x axis, y axis, width, height
f.add(action);//adding button in JFrame
f.add(label);
action.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
if(x){
x = false; //Update x here
action.setText("Play");
action.revalidate();
}else{
x = true; //Update x here also
action.setText("Pause");
action.revalidate();
if(x){ //Using x here to determind whether we should start our child thread or not.
(new Thread(new Child())).start();
}
}
}
});
f.setSize(500, 700);//500 width and 700 height
f.setLayout(null);//using no layout managers
f.setVisible(true);//making the frame visible
}
}
class Child implements Runnable{
#Override
public void run() {
while (x) {
//You can put your long task here.
i++;
label.setText(i+" Secs");
label.revalidate();
try {
sleep(1000); //Sleeping time for our baby thread ..lol
} catch (InterruptedException ex) {
Logger.getLogger("No Foo");
}
}
}
}
I'm trying to create a sequence of actions to simulate eye blinking of my character but I have no idea how to properly do this. I need it to stand still for like 5 secs, then blink once and wait for 5 seconds again and loop forever. Hope someone could shed some light here.
This is what I've got so far which doesn't work to what I have expected (After 3f, it will keep blinking, how do I detect blinking animation end and reset back to stand?):
this.addAction( Actions.sequence(
Actions.run( new Runnable() {
#Override
public void run() {
stand();
}
}),
Actions.delay(.3f),
Actions.run( new Runnable() {
#Override
public void run() {
blink();
}
})));
Libgdx has a class RepeatAction, which is what you are looking for.
Basicly you need to call:
this.addAction(Actions.forever(Actions.sequence(
Actions.run(new Runnable {
#Override
public void run() {
stand();
}
}),
Actions.delay(0.3f),
Actions.run(new Runnable {
#Override
public void run() {
blink();
}
});
)));
But instead of using new Runnable you may use one of the methods provided by Libgdx Actions.
So for example, the stand(), isn't it only "do nothing"? This can be achieved with an Actions.delay(5f), which waits for 5 seconds.
And the blink() isn't it only switching from "visible" to "invisible"?
This could be don with Actions.alpha(0, 0.2f), which changes the characters transparency from its current to 0 in 0.2 seconds. Then you could add another delay to let the character "wait" in the invisible state and make it visible again with Actions.alpha(1, 0.2f).
Hope it helps.
I already have a post related to the multithreading issue but I have some new questions+code. I have a multiball game project and it requires me to parse an XML file to obtain information about the ball(like size, speed, initial position etc). Now, I wanted to create a different thread to parse the XML file, but I cannot figure out a way to do it. Here is my code:
main() starts here:
public class BounceBallApp extends JFrame{
public BounceBallApp()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("BounceBallApp");
setSize(300,300);
setVisible(true);
add(new BallWorld());
validate();
}
public static void main(String[] args)
{
/*Create main GUI in the Event Dispatch Thread*/
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new BounceBallApp(); //main frame
}
});
}
}
Within the constructor for BallWorld(), I have an inner class BallContainer(), which contains a Start button:
jbtStart.addActionListener(new ActionListener()
{public void actionPerformed(ActionEvent e)
{
//Populate the ballList arraylist
if(filePathField.getText().equals(" "))
{
JOptionPane.showMessageDialog(null, "Please input the XML file","Information", JOptionPane.INFORMATION_MESSAGE);
}
else
{
XMLFilePath = filePathField.getText();
ballList = new BallList(XMLFilePath);//I want to put this in a thread
JOptionPane.showMessageDialog(null,"Game started!","Bouncing Balls",JOptionPane.INFORMATION_MESSAGE);
for(Ball ball:ballList.ballsArrayList)
{
timer.setDelay(1000/ball.getSpeed()); //change the delay of the timer to the ball's speed
timer.start(); //start the timer
bTimer = true; //timer is now on
}
}
}
});
}
Now the problem is that if I put the parsing process in another thread, then I have to wait for the ballsArrayList to fill before I can continue with the application. I was thinking of using invokeAndWait() but I read that that method cannot be called from the Event Dispatch Thread. So, How can I achieve this? Or is it even worthwhile?
Also, I wanted to move the calculation for moving the ball (calculating the x,y coords) to a thread, but again, I don't know how to implement it.
for(Ball ball:ballList.ballsArrayList)
{
ball.draw(g);
ball.move(ballContainerWidth,ballContainerHeight,buttonPanel.getHeight());
}
public void move(int ballContainerWidth,int ballContainerHeight,int buttonPanelHeight)
{
if((this.getX()+this.getsize()+this.getDx()) > ballContainerWidth)
{
this.setDx(-Math.abs(this.getDx()));
}
//the height/depth to which the balls can bounce is the (main ball container height) minus (button panel height)
if((this.getY()+this.getsize()+this.getDy()) > ballContainerHeight-buttonPanelHeight)
{
this.setDy(-Math.abs(this.getDy()));
}
if((this.getX()-this.getsize()) < 0 )
{
this.setDx(Math.abs(this.getDx()));
}
if((this.getY()-this.getsize()) < 0 )
{
this.setDy(Math.abs(this.getDy()));
}
int newX = (int)Math.round((this.getX()+this.getDx()));
int newY = (int)Math.round((this.getY()+this.getDy()));
this.setX(newX);
this.setY(newY);
}
Sorry for the long post, but multithreading is all new to me. I am a bit confused about it.
Initial loading of the files
I personally would opt for one of the following approaches
Increase the start-up time of your program by parsing all the files during start-up. For a few XML files this overhead might be very small. If it takes too long, you can consider showing a splash screen
Load the XML files when the start button is pressed, but show a progress bar until the loading is done. Start the game afterwards. A SwingWorker can help you with this. Examples can be found in the Swing documentation or here on SO.
Updating of the ball position
If the calculation is as easy as what is shown here, I would simply use a javax.swing.Timer to update the position on regular time intervals, and do the calculation on the Event Dispatch Thread.
If you want to do the calculation on a background thread just for the exercise, I would still opt for a calculation of the position on a background thread. The calculation should be using local variables which are only know to that background thread. Once the new position is calculated, update the position of the ball on the Event Dispatch Thread using SwingUtilities#invokeLater. This allows you to access the position during the paint operation without having to worry about threading issues. Probably easier then messing around with locks.
I am making a game having squares in it (a grid of panels) and when the game ends there is an algorithm that changes the color of the panels one by one in a "live" fashion where the user watches the squares change color slowly. I try something like:
Thread.sleep(1000);
grid.getComponent(boxNumber).setBackground(Color.YELLOW);
Thread.sleep(1000);
grid.getComponent(boxNumber).setBackground(Color.ORANGE);
Although the color of a box changes to Yellow, it does not change to Orange afterwards. Anyone have any ideas? Hope I was able to be clear.
Read the section from the Swing tutorial on Concurrency to understand why you should not be using the sleep() method.
One solution is to use a SwingWorker, then you can 'publish' the color of the component so it can be updated properly on the EDT and you can invoke the sleep() method in the worker as well.
These need to happen on the Swing event thread. call set background via:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
grid.getComponent(boxNumber).setBackground(Color.ORANGE);
}
});
Note, your Thread.sleep() should not be in the event thread (or directly from within a Swing event listener (ActionListener, WindowListener, etc).
It would also be prudent to look the Swing Timing Framework which is specifically for things like this.
-Generally its not a good idea to do Thread.sleep(1000); in the EDT. You should try using Timers.
-You also need to call revalidate()/validate() and repaint() afterward.
So maybe something like this:
Timer yellowTimer = new Timer(1000,new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
jtp.setBackground(Color.YELLOW);
//call revalidate()/validate() and repaint() afterward
jtp.revalidate();
jtp.repaint();
}
});
yellowTimer.setRepeats(false);
Timer orangeTimer = new Timer(2000,new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
jtp.setBackground(Color.ORANGE);
//call revalidate()/validate() and repaint() afterward
jtp.revalidate();
jtp.repaint();
}
});
orangeTimer.setRepeats(false);
yellowTimer.start();
orangeTimer.start();
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);