In my onTouchEvent method (in a class that extends Activity), I have some imageViews that change one by one, which is done by waiting a little before executing the next change.
//in the onTouchEvent method
//ivList is an arrayList of imageViews
ivList.get(0).setImageResource(R.drawable.drawable1);
synchronized (this) {
try {
wait(500);
} catch (InterruptedException e) {
}
}
ivList.get(1).setImageResource(R.drawable.drawable2);
However, when this is executed, the changes only take place once onTouchEvent is concluded, so the result is a minor delay and then both imageViews change at once, as opposed to one imageView changing, a minor delay, and then the second one changes. Can someone explain how to fix this?
The problem is you should not use wait() because it will block the main thread
ivList.get(0).setImageResource(R.drawable.drawable1); // this is doing in main thread
synchronized (this) {
try {
wait(500); // this blocks the main thread
} catch (InterruptedException e) {
}
}
ivList.get(1).setImageResource(R.drawable.drawable2); // this is also doing in main thread
try following
Runnable r = new Runnable() {
#Override
public void run() {
ivList.get(1).setImageResource(R.drawable.drawable2);
}
};
ivList.get(0).setImageResource(R.drawable.drawable1);
// no synchronized is needed
new Handler().postDelayed(r,500); // call to change the image after 500s
of cause your Runnable and Handler can create else where so that you do not need to create them every time the onTouchEvent is trigeered
okay , if you are going to make it work for 10 images.
// these are local variables
//create a contant int array for the 10 images
int[] imgs = {R.drawable.drawable1 , R.drawable.drawable2 ,....,R.drawable.drawable10};
int count = 0; // counting which image should show
// local variable ends
// initialize
Handler handler = new Handler();
Runnable r = new Runnable() {
#Override
public void run() {
if (count < 9){
count++;
ivList.get(count).setImageResource(imgs[count]);
handler().postDelayed(r,500);
}
}
};
// in your touch event
ivList.get(0).setImageResource(R.drawable.drawable1);
// no synchronized is needed
handler().postDelayed(r,500); // call to change the image after 500s
Related
Lets say I have a ImageView that executes at a click of a Button:
final ImageView ball = new ImageView(v.getContext());
ball.setImageResource(R.drawable.ball_1);
gameConstraintLayout.addView(ball);
When I click that button, it first off makes the ball appears , creates and runs another thread that tell itself to sleep 1000 milliseconds sleep(long millis) then removes the ball by calling ConstrainLayout.removeView(view)
Here is the full minimal code:
final ImageView ball = new ImageView(v.getContext());
currentBullet.setImageResource(R.drawable.ball_1);
gameConstraintLayout.addView(ball);
ballAppears.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
final ImageView ball = new ImageView(v.getContext());
currentBullet.setImageResource(R.drawable.ball_1);
gameConstraintLayout.addView(ball);
Thread thread = new Thread() {
#Override
public void run() {
try {
sleep(1000);
contraintLayout.removeView(ball)
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
});
Problem is;
The ball appears on screen, the other thread successfully sleeps for 1000 milliseconds, but, It crashes when It tries to remove the ball from the constraint layout in the other thread.
Logcat:
android.view.ViewRootImpl$CalledFromWrongThreadException: **Only the original thread that created a view hierarchy can touch its views**.
at android.support.constraint.ConstraintLayout.removeView(ConstraintLayout.java:645)
at com.mobilegames.***.******.GameActivity$1$1.run(GameActivity.java:51)
The code that causes the problem is:
gameConstraintLayout.removeView(ball_1);
AS it seems,I cant access the Constraint layout from the other thread but, I can still change the X and the Y of the ball.
I even tried running that piece of code in the UI theard runOnUIThread(...), but to no avail.
Here is the runONUIThread code:
shootTank.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
final ImageView currentBullet = new ImageView(v.getContext());
currentBullet.setImageResource(R.drawable.bullet_model1);
gameConstraintLayout.addView(currentBullet);
Thread thread = new Thread() {
#Override
public void run() {
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
public void run() {
gameConstraintLayout.removeView(currentBullet);
}
});
}
};
thread.start();
}
});
Any possible solutions? Keep in mind that I change the X and Y's of the ball after every second.
AND YES, I did check other Questions. The answer in those ones said to simply run it on the UI thread, but of course I already tried that. If i run the sleep(long millis) into the UI thread, obliviously, the whole app would be irresponsible.
(This is not the full app; it was broken down into a much more simpler and understandable Question. I end up changing the ball's X and Y in the separate thread, but that inst what is causing the problem. Please tell me in comments if editing is necessary)
Sorry for small grammar mistakes
Use handler to perform your actions with some delay. For example:
Handler h = new Handler();
h.postDelayed(new Runnable() {
public void run() {
gameConstraintLayout.removeView(currentBullet);
}
}, 1000); // here 1000 is delay in milliseconds (1sec)
After searching for an answer lots of threads about similar issues, I still don't find a solution that fits my needs.
Basically, I have a while loop and I'd like to wait for the repaint() method to complete before another iteration of that loop starts.
In more detail, I have some segments that are drawn in the paintComponent method of a MapPanel class that extends JComponent.
Then, when the user clicks on a button, an algorithm starts searching for intersections beginning with the "upper" segments (using endpoints as event points).
This algorithm is basically the while loop I spoke about, it calls another algorithm in this while loop sending one event point at each iteration (those event points are sent in order, from top to bottom).
What I'd like to do is to show the current "position" of the algorithm by drawing a line at the current event point.
As the algorithm finds new intersections, I'd like to show them too.
I did draw what was needed in the paintComponent() method.
The problem is that when I call the repaint() method for the MapPanel inside the loop, it waits for the whole loop to end before the UI is updated(I've found a lot about why it does that but not about how to fix this in my particular case).
Okay, I'm done with the explanations, here's the actual algorithm :
private void findIntersection(ArrayList<Segment> segments){
QTree Q=new QTree();
for (Segment s : segments){
Q.initialise(s);
}
TreeT T=new TreeT();
while (Q.getRoot()!=null){
Point p = Q.maxEventPoint(Q.getRoot());
Q.delete(p.getX(), p.getY());
mapPanel.setSweeplinePosition(p.getY());
handleEventPoint(p, T, Q);
mapPanel.repaint()
//should wait here for repaint() to complete
}
System.out.println("all intersections found, found " + mapPanel.getIntersections().size());
}
The problem is that your long-running code is likely being called on the Swing event thread an action which prevents the event thread from doing its actions including drawing the GUI.
The solution is likely similar to what you've found in your search, but we don't know why you cannot use it with your program, and that is to do the while loop in a SwingWorker background thread, to publish the interim results using the SwingWorker's publish/process method pair, and then to do your drawings with the interim data.
For more on this, please read Concurrency in Swing
For example
private void findIntersection(final ArrayList<Segment> segments) {
final SwingWorker<Void, Double> myWorker = new SwingWorker<Void, Double>() {
#Override
protected Void doInBackground() throws Exception {
QTree Q = new QTree();
for (Segment s : segments) {
Q.initialise(s);
}
TreeT T = new TreeT();
while (Q.getRoot() != null) {
Point p = Q.maxEventPoint(Q.getRoot());
Q.delete(p.getX(), p.getY());
publish(p.getY()); // push data to process method
// take care that this method below does not
// make Swing calls
handleEventPoint(p, T, Q);
}
return null;
}
#Override
protected void process(List<Double> chunks) {
for (Double yValue : chunks) {
// this is called on the EDT (Swing event dispatch thread)
mapPanel.setSweeplinePosition(yValue);
mapPanel.repaint();
}
}
};
myWorker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
// get notified when Worker is done
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
// TODO: any clean up code for when worker is done goes here
try {
myWorker.get(); // must call to trap exceptions that occur inside worker
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
});
myWorker.execute(); // execute worker
}
Did you try with the method Thread.sleep(milliseconds)???
For example, I'm used to do something like this in my code:
btnNewButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
pca.setIcon(new ImageIcon("icon.png"));
for(int i=0; i<4; i++) {
try{Thread.sleep(700);} catch(InterruptedException er){}
x+=20;
p.repaint();
}}
}).start();
}
});
I am attempting to make an application that retrieves images and .mp3 files and transitions from one image to the next once the audio has finished. The underlying framework of how I transition between these images is a little convoluted, but I have managed to get an action in SWT that successfully enables me to manually transition from one to the next. However, a problem has arisen when I've tried to automate it; when placed into a loop, my playAudio() method begins before all of the calls I make in my displayShow() method have resolved, which results in a blank window, despite the audio still playing.
Here is the run method for the action that I want to start the show:
Action startAction = new Action("Start") {
public void run() {
//do {
displayShow();
playAudio();
//} while(true);
}
};
Here is playAudio(). I am able to PLAY the audio without incident:
public void playAudio() {
final String audio = "Happy_Birthday.mp3";
audioLatch = new CountDownLatch(1);
audioThread = new Thread() {
public void run() {
try {
Player player = new Player
(new BufferedInputStream
(new FileInputStream(audio)));
player.play();
audioLatch.countDown();
} catch (JavaLayerException e) {
} catch (FileNotFoundException e) {
} catch (Exception e) {
}
}
};
audioThread.start();
try {
audioLatch.await();
} catch (InterruptedException e) {
}
}
And here is displayShow():
private void displayShow() {
new Thread() {
public void run() {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
Control[] children = container.getChildren();
for (int i = 0; i < children.length; i++) {
children[i].dispose();
}
show.showSlide(container);
container.layout();
}
});
}
}.start();
}
show.showSlide returns a composite whose parent is container, which is the immediate child of the highest parent composite. Within the newly created composite, an image is added to a label and the label's parent is assigned to composite. I realize whether displayShow() is in a separate thread or not seems to be immaterial; this was just the last thing I tried.
It is not solely the addition of the loop that causes the refresh to not execute. The only way I can get the manual transition to work is if I remove the CountDownLatch from the playAudio() method. Were I to remove this latch, the only way to encase these two methods in a loop would be embedded while loops, which seem to hog a fair amount of the CPU and still does not solve my problem. Am I missing anything?
The audioLatch.await() is blocking the main program thread, this is the thread that all SWT operations run on so the Display.asyncExec runnables are just being queued until the thread is available.
If you really must wait in the playAudio method you could run the display event loop there until the background thread is finished:
while (! background thread finished)
{
if (!display.readAndDispatch())
display.sleep();
}
i have action list which is a ArrayList. Object Action contains 3 parameters(button, action, time_it_takes). So what i have to is get a action form ArrayList perform it and wait for a while and then next action and so on. I have tried but nothing is updating in view it just hang for sometime and nothing updated. I have tried runOnUiThread but it also gives me error. Actually, i think i have weak multithreading concepts. Here is what i am trying...
public void replay()
{
ArrayList<Action> actions = gui.getActionList();
for(i =0; i<actions.size(); i++)
{
gui.Replay(actions.get(i));
try
{
Thread.sleep(actions.get(i).getTime()); // delay for the next task
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Help Please
From your comments you are calling replay() from your activity which runs on the ui thread
You are calling sleep on the ui thread which blocks the ui thread. You should not block the ui thread. Do not call Thread.sleep(2000) in the ui thread.
http://developer.android.com/training/articles/perf-anr.html
You can use a Handler if you wish you execute something every few seconds.
Handler m_handler;
Runnable m_handlerTask ;
m_handler = new Handler();
m_handlerTask = new Runnable()
{
#Override
public void run() {
// do something every 1 second
m_handler.postDelayed(m_handlerTask, 1000);
}
};
m_handlerTask.run();
To cancel the run
m_handler.removeCallbacks(m_handlerTask);
how to set the value of jprogressbar to zero after reached the 100%?
i used the following code but didn't do exactly what i want:
private void jButton6ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
Thread runner = new Thread(){
#Override
public void run(){
counter = pb_MINIMUM;
while(counter <= pb_MAXIMUM){
Runnable runme = new Runnable(){
public void run(){
jProgressBar1.setValue(counter);
}
};
SwingUtilities.invokeLater(runme);
counter++;
try{
Thread.sleep(100);
}catch(Exception e){
}
}
}
};
runner.start();
if(jProgressBar1.getMaximum()==pb_MAXIMUM){
jProgressBar1.setValue(0);
}
}
thanks for any help i could get here...
Your call of setValue(0) occurs directly after you started the thread (which does all the work and increases value of progress bar). At this time no work was done yet and the method does not wait for your thread to complete. Instead you may just include the code right after your while loop (same as you do inside but with value of zero).