Android Java draw to canvas each millisecond - java

I want to draw in some Activity. I've used threads with SurfaceViews, but it doesn't push changes at all! Here you can see my previous things:
Canvas canvas = null;
try {
canvas = this.surfaceHolder.lockCanvas();
synchronized (canvas) {
this.gameSurface.update();
this.gameSurface.draw(canvas);
}
} catch (Exception e) {
// Do nothing.
} finally {
if (canvas != null) {
canvas.drawColor(Color.BLACK);
this.surfaceHolder.unlockCanvasAndPost(canvas);
}
}
try {
sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
(Thread handling example - I've checked, it'd drown only first time, but then it had not pushed any changes). So, should I change SurfaceView to something else, or this is a good solution and I have to find errors?

I've decided to stay on clear android engine. I've fixed all my problems with canvas redrowing. If anyone have some issues: just push changes inside SurfaceView to itself, just like this:
public void update() {
invalidate();
Canvas canvas = getHolder().lockCanvas(null);
this.draw(canvas);
getHolder().unlockCanvasAndPost(canvas);
}

Related

Count integer with Thread in Activity and update Canvas in View

I'm developing my first android game without xml files for layouts in eclipse. This is calling MyGameView.class(extends View) from MyGameActivity.class(extends View implements OnTouchListener)
MyGameView myView;
myView = new MyGameView(this);
myView.setOnTouchListener(this);
setContentView(myView);
Everytime, I touch (MotionEvent.ACTION_DOWN), I update the Canvas in MyGameView.class with the following code. This is the code I use to update MyGameView.class from MyGameActivity.class.
myView.invalidate();
Yes it works!But I got a serious problem now.I need to move Canvas in MyGameView.class by every 0.3 second.I use Thread to update but it forced stop!!!! I tried again and again and again! I failed!
public void runtime() {
i = 0;
Thread timer = new Thread(new Runnable() {
#Override
public void run() {
while (i<1500) {
try {
Thread.sleep(300);
}
catch (InterruptedException e) {
e.printStackTrace();
}
finally {
if (right) {
i++;
//This is static int a from MyGameView.
MyGameView.a += 2;
myView.invalidate();
}
else {
i = 1500;
}
}
}
}
});
timer.start();
}
Updating Static int or boolean to MyGameView.class from MyGameActivity.class with myView.invaldate(); is working. But I can't control it with Thread! Is there something wrong with my Thread running code?
It's probably up to Thread because I can move +2 along X-axis to right everytime I press (MotionEvent.ACTION_DOWN).
//I can Move with this code but not with Thread!
case MotionEvent.ACTION_DOWN:
MyGameView.a += 2;
myView.invalidate();
break;
With Thread, it stops! Please give me a solution for this! In other words, I need to count with time without error and update canvas on every count!
Invalidate must be called from the UI thread. Try calling
postInvalidate()
instead.
See this for reference.

Creating new Thread to update JLabel and setIcon() in said separate Thread

Trying to get an image from another application sending an array of bytes through socket, translating it to a BufferedImage and setting a JLabel in the GUI that updates every 3 seconds.
I tried looking it up on forums but questions regarding graphical update are recurrent to me and I never seem to get it right -- there's at least 6 update methods in java for graphical interface and every one I tried won't work.
I know the problem isn't in the connection to the client because I can easily save the image I receive with ImageIO.write() and it updates every 3 seconds to the image I was expecting to receive. I just can't have Java updating the JLabel correctly without having to go to forums and ask people. Such a complex task I guess. Here is the code: http://pastebin.com/95nMGLvZ. I am doing this project in Netbeans so there's a lot of stuff in there that is unnecessary to read as it does not directly relate to the problem.
I think the answer lies in creating a separate thread to update my JLabel from the ever-changing BufferedImage that is received from the ObjectInputStream. Anyone mind giving me a hand at this? What is better for my code? SwingWorker, Threading (wtf is setDaemon(flag)?), Runnable, Timer, invokeLater? Tried all of this. Not correctly apparently.
EDIT1:
Tried your answer immibis:
public void startRunning() {
try {
server = new ServerSocket(666, 10);
connection = server.accept();
networkStatus("Connected to " + connection.getInetAddress().getHostName());
Thread thr = new Thread(new Runnable() {
#Override
public void run() {
try {
input = new ObjectInputStream(connection.getInputStream());
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, ex.toString());
}
}
});
thr.start();
System.out.println(!connection.isInputShutdown());
while (connection.isConnected()) {
try {
byte[] byteImage = (byte[]) input.readObject();
InputStream in = new ByteArrayInputStream(byteImage);
final BufferedImage bi = ImageIO.read(in);
jLabel_screen.setIcon(new ImageIcon(bi));
ImageIO.write(bi, "jpg", new File("C:\\Users\\User\\Desktop\\test.jpg"));
System.out.println("i'm working");
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, ex.toString());
} catch (ClassNotFoundException ex) {
Logger.getLogger(SpyxServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, ex.toString());
}
}
It does not work. It says byte[] byteImage = (byte[]) input.readObject(); line has a NullPointerException. The only value that can be null is the return from readObject(), meaning either the input was not initialized correctly or the connection is not synchronized. I hope it's the first option because I wouldn't know how to handle the last.
EDIT2:
Tried your answer blazetopher:
public void startRunning() throws IOException {
server = new ServerSocket(666, 10);
try {
connection = server.accept();
networkStatus("Connected to " + connection.getInetAddress().getHostName());
input = new ObjectInputStream(connection.getInputStream());
while (true) {
try {
byte[] byteImage = (byte[]) input.readObject();
InputStream in = new ByteArrayInputStream(byteImage);
final BufferedImage bi = ImageIO.read(in);
SwingUtilities.invokeLater(new Runnable() {//<-----------
#Override
public void run() {
jLabel_screen.setIcon(new ImageIcon(bi));
}
});
ImageIO.write(bi, "jpg", new File("C:\\Users\\User\\Desktop\\test.jpg"));
System.out.println("i'm working");
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, ex.toString());
} catch (ClassNotFoundException ex) {
Logger.getLogger(SpyxServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
} catch (EOFException eofException) {
networkStatus("Connection Closed. :(");
} finally {
input.close();
connection.close();
}
}
Using SwingUtilities.invokeLater didn't work either. At least the program runs and can even save the image but still can't update the JLabel. Am I running out of options here?
EDIT3:
Tried Jordan's code:
#Override
public void paint(Graphics g) {
g.drawImage(biGlobal, 0, 0, null);
}
The GUI kind of crashed and was "drawing" the components just when I had my mouse cursor hovering it. When I started the code, it did not crashed (+1) but it did not draw anything, even when I try to hover the cursor into where the BufferedImage should be painted. Maybe I should add revalidate() or repaint after calling the Overwritten paint(getGraphics()) inside the startRunning() method?
EDIT4: the while(true) that the code is actually in may be the problem but when I use a SwingTimer it gets out of sync with the client and crashes after first cycle. Any alternatives to this?
Generally speaking you have a producer/consumer pattern. Something is producing images and something wants to consume images. Normally, the consumer would wait on the producer to tell it something has been produced, but in this case, we can use a observer pattern instead, having the producer notify the consumer that something was been produced (instead of waiting for it)
We need someway for the producer to communicate with the consumer...
public interface PictureConsumer {
public void newPicture(BufferedImage img);
}
You would create an implementation of this in your UI code, this would then set the icon property of the JLabel
Now, we need something to produce the images...
public class PictureProducer extends SwingWorker<Object, BufferedImage> {
private PictureConsumer consumer;
public PictureProducer(PictureConsumer consumer) {
this.consumer = consumer;
}
#Override
protected void process(List<BufferedImage> chunks) {
// Really only interested in the last image
BufferedImage img = chunks.get(chunks.size() - 1);
consumer.newPicture(img);
}
#Override
protected Object doInBackground() throws Exception {
/*
This whole setup worries me. Why is this program acting as the
server? Why aren't we pooling the image producer?
*/
try (ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(666, 10)) {
try (Socket socket = server.accept()) {
try (ObjectInputStream ois = new ObjectInputStream(socket.getInputStream())) {
// Using `while (true)` is a bad idea, relying on the fact
// that an exception would be thrown when the connection is closed is
// a bad idea.
while (!socket.isClosed()) {
// Generally, I'd discourage using an ObjectInputStream, this
// is just me, but you could just as easily read directly from
// the ByteArrayInputStream...assuming the sender was sending
// the data as a byte stream ;)
byte[] bytes = (byte[]) ois.readObject();
try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes)) {
BufferedImage img = ImageIO.read(bis);
publish(img);
}
}
}
}
}
return null;
}
#Override
protected void done() {
try {
get();
} catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null, "Image Producer has failed: " + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
}
}
}
See Worker Threads and SwingWorker for more details
You can a reverse example of this (where some server is producing images and a client is consuming them) here
To update your label, you want to ensure you're using the EDT thread, so use SwingUtilities.invokeLater from the code where you're receiving the BufferedImage (which would ideally be in a separate "worker" thread:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
// Update your label here
}
});
What is it you are attempting to accomplish.there might be a better way all together.
For example replace the JLabel with a JPanel then use that JPanel paint method
#Override
public void paint(Graphics g) {
g.drawImage(Img, xcord, ycord, null);
}
Then make that JPanel implement runnable and do your updates in that run method.
JPanel class
public class GraphicsPanel extends JPanel{
private BufferedImage img;
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D G2D = (Graphics2D) g;
G2D.drawImage(img, 0, 0, null);
}
public void setImg(BufferedImage img) {
this.img = img;
}
}
then make sure this panel is visible from wherever you wish to call its methods.
this will look something like this
GraphicsPanel graphicsPanel = new GraphicsPanel();
boolean running;
BufferedImage srcImage;
public void run(){
while(running){
graphicsPanel.setImg(srcImage);
graphicsPanel.repaint();
try {
Thread.sleep(300);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

Android app crashes on reopen

I made a 2D android game for android and the game works perfectly fine but upon reopening it after closing, the game crashes once (Unfortunately, game has stopped working appears) before working again. This only occurs on newer devices, as I tested it on an API level 8 smaller screen and this does not happen.
I suspect this has something to do with how I use the Bitmap resources for the game. I do not release the resources anywhere in the code, is this something that I should be doing or does the garbage collector automatically handle it?
The game reopens fine on all emulator devices except for the occasional
Exception locking surface
java.lang.IllegalStateException: Surface was already locked
that is thrown on reopen. I do not know the fix for this but it happens very rarely.
Here is the code in the MainThread.java class
while (running) {
startTime = System.nanoTime();
canvas = null;
try {
canvas = this.surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
// update game state
this.gamePanel.update();
// draws the canvas on the panel
this.gamePanel.draw(canvas);
}
} catch(Exception e){e.printStackTrace();}finally {
// in case of an exception the surface is not left in
// an inconsistent state
if (canvas != null) {
try {
surfaceHolder.unlockCanvasAndPost(canvas);
}
catch(Exception e){e.printStackTrace();}
}
}
method that starts the thread:
#Override
public void surfaceCreated(SurfaceHolder holder) {
player = new Player(BitmapFactory.decodeResource(getResources(), R.drawable.helicopter),65,25,3);
bg = new Background(BitmapFactory.decodeResource(getResources(), R.drawable.grassbg1));
smoke = new ArrayList<Smokepuff>();
missiles = new ArrayList<Missile>();
botborder = new ArrayList<BotBorder>();
topborder = new ArrayList<TopBorder>();
explosions = new ArrayList<Explosion>();
smokeStartTime = System.nanoTime();
missileStartTime = System.nanoTime();
thread.setRunning(true);
thread.start();
}
and method that shuts the thread down:
#Override
public void surfaceDestroyed(SurfaceHolder holder)
{
boolean retry = true;
while (retry) {
try {
thread.setRunning(false);
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
retry = false;
}
}
Any help would be greatly appreciated!

Repainting Continuously in Java

I have a Java program that uses threads. In my run method, I have:
public void run() {
while(thread != null){
repaint();
System.out.println("hi");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
}
}
public void paintComponent(Graphics g) {
// painting stuff
}
The problem is that the run method is executed, but the paintComponent section is not called. If this is not the right way to keep repainting the component, then how should I repaint it?
Cal repaint from a Swing Timer. That will not block the GUI, and will happen at whatever interval specified in the timer. Of course, by the nature of Swing/AWT painting, if the timer is set to repeat too fast, calls to paint might be coalesced (effectively ignored).
Also, make sure the method is an override using:
#Override
public void paintComponent(Graphics g){
You should only repaint a component when you need to (ie, when you update it).
Depending on what you're doing, you might also be interested in this. This is taken from Killer Game Programming in Java by Andrew Davison. He talks about active rendering. Your game loop is effectively:
public void run()
{
while (running)
{
gameUpdate(); // game state is updated
gameRender(); // render to a buffer
paintScreen(); // draw buffer to screen
try
{
Thread.sleep(20);
}
catch (InterruptedException e) {;}
}
}
And, the implementation of paint screen is (defined by a subclass of JComponent):
private void paintScreen()
{
final Graphics2D g2d;
try
{
g2d = (Graphics2D) this.getGraphics();
if (g2d != null && (backbuffer != null))
{
g2d.drawImage(backbuffer, 0, 0, null);
}
Toolkit.getDefaultToolkit().sync(); // sync the display on some systems [1]
g2d.dispose();
}
catch (Exception e)
{
;
}
}
From the book:
[Note 1] The call to Tookkit.sync() ensures that the display is promptly updated. This is required for Linux, which doesn't automatically flush its display buffer. Without the sync() call, the animation may be only partially updated, creating a "tearing" effect.
You have to call paint(g) for a heavy-weight container such as a JFrame. You call paintComponent(g) for light-weight containers like a JButton. See if that works.

jpanel dont draw a buffered image but the buffered image can be created as file

Hi i have a jpanel to draw on. from this jpanel i make bufferedimages and safe them into a linkedlist. on a button press i want to animate this bufferedimages(play one after one)
the problem is that the jpanel dont show the buffered images but when i use ImageIO.write to safe the bufferedimages on disk i get all the pictures i want to animate. pls help me.
here is my code:
public void run(){
for(int i=0;i`<`cm.animationListe.size();i++){
b= cm.animationListe.get(i);
try {
ImageIO.write( b, "png", new File( "c:/java/circle"+i+".png" ) );
} catch (IOException e1) {
e1.printStackTrace();
}
try {
Thread.sleep(1000);
repaint();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}}
animation = false;
}
public void paintComponent(Graphics g){
super.paintComponent(g);
if(animation){
g.drawImage(b,0, 0,null);
}
}
The Thread.sleep() causes the GUI to freeze so it can't repaint itself.
To do animation you need to use a Swing Timer.

Categories