Most efficient way to blink a light - java

I have a simple Component that I want to blink everytime my application receives a "message". Currently I am creating a new thread to 'light' the Component, sleep, then reset the Component. How could I accomplish this in a better way? I know that threads are expensive.
public class StatusLights extends JComponent {
private static final Color unlit = Color.lightGray;
private HashMap<String, Color> colors = new HashMap<String, Color>();
public StatusLights() {
// start with no colors
colors.put("TOP", unlit);
colors.put("MIDDLE", unlit);
colors.put("BOTTOM", unlit);
}
// 1 = top 2 = mid 3 = bottom
public void light(Color color, int pos) {
switch (pos) {
case (1): {
colors.put("TOP", color);
break;
}
case (2): {
colors.put("MIDDLE", color);
break;
}
case (3): {
colors.put("BOTTOM", color);
break;
}
default: {
// not valid position
}
}
repaint();
}
public void clear() {
colors.put("TOP", unlit);
colors.put("MIDDLE", unlit);
colors.put("BOTTOM", unlit);
repaint();
}
public void blink(final Color color, final int i) {
new Thread(new Runnable() {
public void run() {
light(color, i);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
clear();
}
}).start();
}
}

Use a Swing javax.swing.Timer, it's repeatable at a regular time interval, provides a level of thread isolation/synchronisation (as it timer event is enqueued in the event queue and execute within the context Event Dispatching Thread one at a time) and prevents any possibility of violating Swings single thread rules.
An alternative is to use a SwingWorker and make use of its publish/process methods...

Related

Java android - ImageView scrolling causes crashing?

I have a function which is meant to scroll my Image-view so that it falls 5 pixels every 0.1 seconds, however as soon as I run this function I get Sorry Application has stopped responding
You can check my code below.:
void startGameLoop(){
boolean alive=true;
while(alive){
int x = theSprite.getScrollX();
int y = theSprite.getScrollY();
y-=5;
theSprite.scrollTo(x, y);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Any help on this would be much appreciated.
If you put this code Thread.sleep(100); on the main thread that will happen.
Use a Handler with delay instead. The handler can change things like ImageView because it operates on the main Ui Thread.
Something like this..
private final Runnable timerRunnable = new Runnable() {
#Override
public void run() {
int x = theSprite.getScrollX();
int y = theSprite.getScrollY();
y-=5;
theSprite.scrollTo(x, y);
if (!closing)
startTimer();
}
};
handler = new Handler();
startTimer();
/**
* Start periodically callbacks.
*/
private void startTimer() {
runOnUiThreadDelay(timerRunnable, 400L);
}
public void runOnUiThreadDelay(final Runnable runnable, long delayMillis) {
handler.postDelayed(runnable, delayMillis);
}

Android Thread.sleep() in AsyncTask freeze UI

i'm tried many suggestions but nothing works! When i call Thread.sleep() in background thread, main thread also freezes for this time (Animation frame drop) :(
Version 1:
public void UpdateChannels(final ArrayList<Channel> channels)
{
new AsyncTask<ArrayList<Channel>, Object[], Void>()
{
#Override
protected Void doInBackground(ArrayList<Channel>... arrayLists)
{
for(Channel channel : arrayLists[0])
{
Integer chid = new Integer(channel.arfcn);
ChannelRect channelRect = Channels.get(chid);
publishProgress(new Object[] {channelRect, channel.dBm});
try
{
Thread.sleep(1000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
return null;
}
#Override
protected void onProgressUpdate(Object[]... values)
{
ChannelRect channelRect = (ChannelRect) values[0][0];
int value = (Integer)values[0][1];
channelRect.setValue(value);
channelRect.Animate();
}
}.execute(channels);
}
Version 2:
public void UpdateChannels(final ArrayList<Channel> channels)
{
new Thread(new Runnable()
{
#Override
public void run()
{
for(final Channel channel : channels)
{
int chid = new Integer(channel.arfcn);
final ChannelRect channelRect = Channels.get(chid);
if(channelRect != null)
{
CurrentActivity.runOnUiThread(new Runnable()
{
#Override
public void run()
{
channelRect.setValue(channel.dBm);
channelRect.Animate();
}
});
try
{
Thread.sleep(500);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
}).start();
}
And i tried same thing with post and Handler. Same thing :( When Thread.sleep(500) arrives animation freezes :(
What i'm doing wrong?
UPDATE 1
Found heavy place that slows UI thread:
I have horizontal LinearLayout that stores 175 ChannelRect views. When i call animate (that starts AlphaAnimation all okay, but when i setValue() to ChannelRect it must change his size:
public void setValue(int value)
{
_value = value;
setOpacity((byte)255);
CurrentLayoutParams.height = (int)((-110 - value) * ycoeff * -1);
requestLayout();
}
This is slow downs main UI thread. Why? setValue affects only one view in this LinearLayout not all...
p.s. removing requestLayot() line remove slowdowns but ChannelRect size not changes :(
The reason why animation freezes it's a requestLayout() in ChannelRect.
Main LinearLayout that contains many (175+) custom views trying to redraw every children on requestLayout() called from updated child.
I'm changed my ChannelRect for drawing rectangle inside view and now calling Invalidate() instead requestLayout():
public void setValue(int value)
{
_value = value;
setOpacity((byte)255);
invalidate();
}
#Override
protected void onDraw(Canvas canvas)
{
canvas.drawRect(0,getHeight() - (int)((-110 - _value) * ycoeff * -1),size,getHeight(), pnt);
}

Getting errors related to threads and arrayLists

Hi im writting a very simple game. Player can use mouse to move spaceship and every 200ms new beam is shoot. This beam is moved in while(true) loop and when its y is 0 or 400 (bounds of frame) i use break to end the loop (and thread). Every beam has its own thread. There are also stars which move in background. Every of them moves like beams and has its own thread. So as you can see there are often add and removes from arrayLists. Everything works but from time to time I get such errors:
Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
at java.util.ArrayList$Itr.next(ArrayList.java:791)
at spacecommander.MainPanel.paintComponent(MainPanel.java:50)
They doesnt make any problems in game but how can I eliminate them? Maybe I should use synchronization or something?
EDIT: HERE IS THE CODE
public class MainPanel extends JPanel {
private Player player = new Player(100, 100, 3, 3);
private Point2D targetPoint = new Point2D.Float(130, 350); //Poczatkowa pozycja statku
private ArrayList<Beam> beams = new ArrayList<Beam>();
private InputMap imap = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
private ActionMap amap = getActionMap();
private Random rand = new Random();
public MainPanel() {
setPreferredSize(new Dimension(300, 400));
addMouseMotionListener(new MouseMotionHandler());
//Rozpoczynanie watkow
Thread t = new Thread(new PlayerMoveRunnable());
t.start();
Thread t2 = new Thread(new PlayerShootRunnable());
t2.start();
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setColor(Color.BLACK);
g2.fillRect(0, 0, 300, 400);
//Rysowanie gracza
g2.drawImage(player.getImage(), (int)player.getX(), (int)player.getY(), null);
//Rysowanie pociskow
for (Beam beam : beams) {
g2.drawImage(beam.getImage(), (int)beam.getX(), (int)beam.getY(), null);
}
}
public void makeShortcut(String name, String keys, AbstractAction action) {
imap.put(KeyStroke.getKeyStroke(keys), name);
amap.put(name, action);
}
//Watek dziala caly czas bo gracz i tak caly czas sie rusza
private class PlayerMoveRunnable implements Runnable {
public void run() {
try {
while (true) {
player.moveToPoint(targetPoint);
repaint();
Thread.sleep(15);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//Takze dziala caly czas. Dodaje nowy pocisk co 200ms
private class PlayerShootRunnable implements Runnable {
public void run() {
try {
while (true) {
//Wybranie pocisku do wystrzelenia w zaleznosci od mode gracza
Thread t;
switch (player.getBeamMode()) {
case 1:
t = new Thread(new BeamMoveRunnable(new Beam1(100, 100, 10, 10, 10)));
break;
}
t.start();
Thread.sleep(200);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private class BeamMoveRunnable implements Runnable {
private Beam beam;
public BeamMoveRunnable(Beam beam) {
this.beam = beam;
}
public void run() {
Beam beam = this.beam;
beams.add(beam);
try {
while (true) {
if (beam.getY() <= 0) {
beams.remove(beam);
break;
}
beam.move();
repaint();
Thread.sleep(20);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private class MouseMotionHandler extends MouseAdapter {
public void mouseMoved(MouseEvent event) {
targetPoint = event.getPoint();
}
}
}
This seems to be a synchronization issue, as you suspected. Probably while your drawing code is iterating the beams-list, a BeamMoveRunnable modifies the list at the same time (either adding or removing a beam), and causes the ConcurrentModificationException. Personally I wouldn't use separate threads to move the beams, but a simple loop which first updates the game (moving all the beams one at a time etc.) and then redraws the screen. However, you can also just synchronize the access to the list so only a single thread can access it at a time.
Since you are using multiple threads different threads are trying to modify your beams arraylist. You can use synchronized block to avoid concurent modification exception as below
Looping the list
synchronized (beams) {
for (Iterator it = beams.iterator(); it.hashNext(); ) {
Beam beam = (Beam) it.next();
g2.drawImage(beam.getImage(), (int)beam.getX(), (int)beam.getY(), null);
}
}
Adding item to the list
syncronized (beams) {
beams.add(beam);
}
removing item from the list
syncronized (beam) {
list.remove(beam);
}
This typically happens when you try to add or remove an item from a list while iterating:
for (String s : list) {
list.add("abc"); //ConcurrentModificationException
}
It is difficult to be more specific without seeing the code that is around line 50 of your MainPanel class (cf. stacktrace: at spacecommander.MainPanel.paintComponent(MainPanel.java:50)).
EDIT
Following your edit, a simple change would be to use a CopyOnWriteArrayList which is thread safe, instead of an ArrayList, to hold your Beam objects.

Swing GUI not updating

I'm writing an application that reads in audio, analyses this data and then displays the results in realtime. Currently I am using a SwingWorker to run the loop that initiates the background analysis and calling the SwingUtilities.invokeLater method inside the loop to update the GUI components each time analysis has completed. At the moment, the GUI seems to be updating randomly, and occasionally not at all.
The following code shows how I'm trying to accomplish this. The TunerListener is an inner class of a JPanel subclass. PrevNote, nextNote, frequency, and the light variables are all components in the JPanel subclass that I want to update:
private class TunerListener implements ActionListener {
private boolean firstUpdate = true;
private boolean executing = false;
private TunerWorker tunerWorker = null;
private final class TunerWorker extends SwingWorker<Void, Void> {
#Override
protected Void doInBackground() {
while (!this.isCancelled()) {
// Audio analysis in worker thread
model.update(firstUpdate);
// Update components in EDT
if (!this.isCancelled()) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
prevNote.setText(model.getPrev());
currentNote.setText(model.getNote());
nextNote.setText(model.getNext());
frequency.setText("Frequency: "
+ model.getFrequency());
switch (model.getOffset()) {
case -2:
light_2.setIcon(onRed);
light_1.setIcon(off);
light0.setIcon(offBig);
light1.setIcon(off);
light2.setIcon(off);
break;
case -1:
light_2.setIcon(off);
light_1.setIcon(onRed);
light0.setIcon(offBig);
light1.setIcon(off);
light2.setIcon(off);
break;
case 0:
light_2.setIcon(off);
light_1.setIcon(off);
light0.setIcon(onGreen);
light1.setIcon(off);
light2.setIcon(off);
break;
case 1:
light_2.setIcon(off);
light_1.setIcon(off);
light0.setIcon(offBig);
light1.setIcon(onRed);
light2.setIcon(off);
break;
case 2:
light_2.setIcon(off);
light_1.setIcon(off);
light0.setIcon(offBig);
light1.setIcon(off);
light2.setIcon(onRed);
break;
}
firstUpdate = false;
}
});
}
}
return null;
}
#Override
protected void done() {
}
};
#Override
public void actionPerformed(ActionEvent ae) {
if (ae.getActionCommand().equals("tune")) {
if (!executing) {
executing = true;
firstUpdate = true;
tune.setText("Stop Tuning");
tunerWorker = new TunerWorker();
tunerWorker.execute();
} else {
tune.setText("Start Tuning");
executing = false;
tunerWorker.cancel(true);
}
}
}
}
Edit
I notice when I use the debugger that I sometimes get to a point where it tells me the source could not be found and in the debugging window it says something about a FutureTask$Sync.innerRun. Does this narrow it down at all?
As an alternative, use an instance of javax.swing.Timer, illustrated here, to Start and Stop the playing of a selected Note, shown here. The play() method feeds a SourceDataLine, which operates asynchronously, and the enum Note makes constructing a JComboBox particularly easy.
final JComboBox combo = new JComboBox();
for (Note note : Note.values()) {
combo.addItem(note);
}
combo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(combo.getSelectedItem());
}
});
this.add(combo);

What is wrong with this applet gameloop?

It seems like this applet will only draw and update DRAWS when the window is resized or minimized. So the applet will not repaint all the time, but only when manipulating the window.
Am I doing something wrong here?
I am following the gameloop presented here: http://www3.ntu.edu.sg/home/ehchua/programming/java/J8d_Game_Framework.html
The code is here:
package newapplet;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GameApplet extends JApplet { // main class for the game as a Swing application
// Define constants for the game
static final int CANVAS_WIDTH = 493; // width and height of the game screen
static final int CANVAS_HEIGHT = 411;
static final int UPDATE_RATE = 4; // number of game update per second
static final long UPDATE_PERIOD = 1000000000L / UPDATE_RATE; // nanoseconds
static int DRAWS = 0;
// ......
// Enumeration for the states of the game.
public enum gameState {
INITIALIZED, CONNECTING, PLAYING, DISCONNECTED
}
private gameState state;
// Define instance variables for the game objects
// ......
// ......
// Handle for the custom drawing panel
private GameCanvas canvas;
// Constructor to initialize the UI components and game objects
public GameApplet() {
// Initialize the game objects
gameInit();
// UI components
canvas = new GameCanvas();
canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
this.setContentPane(canvas);
// Other UI components such as button, score board, if any.
// ......
this.setVisible(true);
}
// All the game related codes here
// Initialize all the game objects, run only once in the constructor of the main class.
public void gameInit() {
// ......
state = gameState.INITIALIZED;
}
// Shutdown the game, clean up code that runs only once.
public void gameShutdown() {
// ......
state = gameState.DISCONNECTED;
}
// To start and re-start the game.
public void gameStart() {
// Create a new thread
Thread gameThread = new Thread() {
// Override run() to provide the running behavior of this thread.
#Override
public void run() {
gameLoop();
}
};
// Start the thread. start() calls run(), which in turn calls gameLoop().
gameThread.start();
}
// Run the game loop here.
private void gameLoop() {
// Regenerate the game objects for a new game
// ......
//state = State.PLAYING;
// Game loop
long beginTime, timeTaken, timeLeft;
while (true) {
beginTime = System.nanoTime();
if (state == gameState.DISCONNECTED) break; // break the loop to finish the current play
if (state == gameState.PLAYING) {
// Update the state and position of all the game objects,
// detect collisions and provide responses.
gameUpdate();
}
// Refresh the display
repaint();
// Delay timer to provide the necessary delay to meet the target rate
timeTaken = System.nanoTime() - beginTime;
timeLeft = (UPDATE_PERIOD - timeTaken) / 1000000L; // in milliseconds
if (timeLeft < 10) timeLeft = 10; // set a minimum
try {
// Provides the necessary delay and also yields control so that other thread can do work.
Thread.sleep(timeLeft);
} catch (InterruptedException ex) { }
}
}
// Update the state and position of all the game objects,
// detect collisions and provide responses.
public void gameUpdate() {
}
// Refresh the display. Called back via rapaint(), which invoke the paintComponent().
private void gameDraw(Graphics2D g2d) {
switch (state) {
case INITIALIZED:
g2d.setColor (Color.red);
g2d.drawString ("init",20,20);
break;
case PLAYING:
g2d.setColor (Color.red);
g2d.drawString ("play",20,20);
break;
case CONNECTING:
g2d.setColor (Color.red);
g2d.drawString ("connecting",20,20);
break;
case DISCONNECTED:
g2d.setColor (Color.red);
g2d.drawString ("disconnect",20,20);
break;
}
g2d.setColor (Color.GREEN);
g2d.drawString ("Re-paint: " + DRAWS,30,30);
this.DRAWS++;
// ......
}
// Process a key-pressed event. Update the current state.
public void gameKeyPressed(int keyCode) {
switch (keyCode) {
case KeyEvent.VK_UP:
// ......
break;
case KeyEvent.VK_DOWN:
// ......
break;
case KeyEvent.VK_LEFT:
// ......
break;
case KeyEvent.VK_RIGHT:
// ......
break;
}
}
// Process a key-released event.
public void gameKeyReleased(int keyCode) { }
// Process a key-typed event.
public void gameKeyTyped(char keyChar) { }
// Other methods
// ......
// Custom drawing panel, written as an inner class.
class GameCanvas extends JPanel implements KeyListener {
// Constructor
public GameCanvas() {
setFocusable(true); // so that can receive key-events
requestFocus();
addKeyListener(this);
}
// Override paintComponent to do custom drawing.
// Called back by repaint().
#Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
super.paintComponent(g2d); // paint background
setBackground(Color.BLACK); // may use an image for background
// Draw the game objects
gameDraw(g2d);
}
// KeyEvent handlers
#Override
public void keyPressed(KeyEvent e) {
gameKeyPressed(e.getKeyCode());
}
#Override
public void keyReleased(KeyEvent e) {
gameKeyReleased(e.getKeyCode());
}
#Override
public void keyTyped(KeyEvent e) {
gameKeyTyped(e.getKeyChar());
}
}
// main
public static void main(String[] args) {
// Use the event dispatch thread to build the UI for thread-safety.
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new GameApplet();
}
});
}
}
Glancing at that code quickly I can see that you are calling repaint() outside of the Event Dispatch Thread, which can cause issues like the one you are seeing. javax.swing.SwingUtilties.invokeAndWait(Runnable r) will allow you to put that repaint() call on the EDT.
http://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html
See this code for a few corrections.
// <applet code='GameApplet' width=400 height=50></applet>
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GameApplet extends JApplet { // main class for the game as a Swing application
// Define constants for the game
static final int CANVAS_WIDTH = 493; // width and height of the game screen
static final int CANVAS_HEIGHT = 411;
static final int UPDATE_RATE = 4; // number of game update per second
static final long UPDATE_PERIOD = 1000000000L / UPDATE_RATE; // nanoseconds
Timer timer;
static int DRAWS = 0;
// ......
// Enumeration for the states of the game.
public enum gameState {
INITIALIZED, CONNECTING, PLAYING, DISCONNECTED
}
private gameState state;
// Define instance variables for the game objects
// ......
// ......
// Handle for the custom drawing panel
private GameCanvas canvas;
// Constructor to initialize the UI components and game objects
public GameApplet() {
// Initialize the game objects
gameInit();
// UI components
canvas = new GameCanvas();
// set the size of the applet in HTML, not the content pane!
canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
this.setContentPane(canvas);
// Other UI components such as button, score board, if any.
// ......
//this.setVisible(true);
}
// All the game related codes here
// Initialize all the game objects, run only once in the constructor of the main class.
public void gameInit() {
// ......
state = gameState.INITIALIZED;
gameStart();
}
// Shutdown the game, clean up code that runs only once.
public void gameShutdown() {
// ......
state = gameState.DISCONNECTED;
}
#Override
public void destroy() {
timer.stop();
}
// To start and re-start the game.
public void gameStart() {
// Create a new thread
//Thread gameThread = new Thread() {
// Override run() to provide the running behavior of this thread.
// #Override
// public void run() {
gameLoop();
// }
//};
// Start the thread. start() calls run(), which in turn calls gameLoop().
//gameThread.start();
}
// Run the game loop here.
private void gameLoop() {
// Regenerate the game objects for a new game
// ......
//state = State.PLAYING;
// Game loop
ActionListener al = new ActionListener() {
long beginTime, timeTaken, timeLeft;
public void actionPerformed(ActionEvent ae) {
beginTime = System.nanoTime();
if (state == gameState.DISCONNECTED) {
//break; // break the loop to finish the current play
System.out.println("do SOMETHING here..");
}
if (state == gameState.PLAYING) {
// Update the state and position of all the game objects,
// detect collisions and provide responses.
gameUpdate();
}
// Refresh the display
repaint();
// Delay timer to provide the necessary delay to meet the target rate
timeTaken = System.nanoTime() - beginTime;
timeLeft = (UPDATE_PERIOD - timeTaken) / 1000000L; // in milliseconds
if (timeLeft < 10) timeLeft = 10; // set a minimum
}
};
timer = new Timer(40,al);
timer.start();
}
// Update the state and position of all the game objects,
// detect collisions and provide responses.
public void gameUpdate() {
}
// Refresh the display. Called back via rapaint(), which invoke the paintComponent().
private void gameDraw(Graphics2D g2d) {
switch (state) {
case INITIALIZED:
g2d.setColor (Color.red);
g2d.drawString ("init",20,20);
break;
case PLAYING:
g2d.setColor (Color.red);
g2d.drawString ("play",20,20);
break;
case CONNECTING:
g2d.setColor (Color.red);
g2d.drawString ("connecting",20,20);
break;
case DISCONNECTED:
g2d.setColor (Color.red);
g2d.drawString ("disconnect",20,20);
break;
}
g2d.setColor (Color.GREEN);
g2d.drawString ("Re-paint: " + DRAWS,30,30);
this.DRAWS++;
// ......
}
// Process a key-pressed event. Update the current state.
public void gameKeyPressed(int keyCode) {
switch (keyCode) {
case KeyEvent.VK_UP:
// ......
break;
case KeyEvent.VK_DOWN:
// ......
break;
case KeyEvent.VK_LEFT:
// ......
break;
case KeyEvent.VK_RIGHT:
// ......
break;
}
}
// Process a key-released event.
public void gameKeyReleased(int keyCode) { }
// Process a key-typed event.
public void gameKeyTyped(char keyChar) { }
// Other methods
// ......
// Custom drawing panel, written as an inner class.
class GameCanvas extends JPanel implements KeyListener {
// Constructor
public GameCanvas() {
setFocusable(true); // so that can receive key-events
requestFocus();
addKeyListener(this);
}
// Override paintComponent to do custom drawing.
// Called back by repaint().
#Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
super.paintComponent(g2d); // paint background
setBackground(Color.BLACK); // may use an image for background
// Draw the game objects
gameDraw(g2d);
}
// KeyEvent handlers
#Override
public void keyPressed(KeyEvent e) {
gameKeyPressed(e.getKeyCode());
}
#Override
public void keyReleased(KeyEvent e) {
gameKeyReleased(e.getKeyCode());
}
#Override
public void keyTyped(KeyEvent e) {
gameKeyTyped(e.getKeyChar());
}
}
}
Note that the addition of the single line comment at the top of the source means that (once compiled) it can be launched from the command line using..
> appletviewer GameApplet.java

Categories